diff options
author | Ted Kremenek <kremenek@apple.com> | 2010-01-27 06:13:48 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2010-01-27 06:13:48 +0000 |
commit | a64e89bbfa756816d1e4a48e5d6c03edf1d7f23b (patch) | |
tree | 627fd4d25e5258ff4b94db400768fd6f384b8794 /lib/Checker/CocoaConventions.cpp | |
parent | f2dd48ca4910e8c4edfc5a2bf4f75f7d7c2a11a0 (diff) |
Start pulling out pieces of the monolithic retain/release checker into
reusable and modular API pieces.
Start by pulling the logic for deriving the Cocoa naming convention
into a separate API, header, and source file.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@94662 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Checker/CocoaConventions.cpp')
-rw-r--r-- | lib/Checker/CocoaConventions.cpp | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/lib/Checker/CocoaConventions.cpp b/lib/Checker/CocoaConventions.cpp new file mode 100644 index 0000000000..456b536d2d --- /dev/null +++ b/lib/Checker/CocoaConventions.cpp @@ -0,0 +1,129 @@ +//===- CocoaConventions.h - Special handling of Cocoa conventions -*- C++ -*--// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines +// +//===----------------------------------------------------------------------===// + +#include "clang/Checker/DomainSpecific/CocoaConventions.h" +#include "llvm/ADT/StringExtras.h" + +using namespace clang; + +using llvm::StringRef; + +// The "fundamental rule" for naming conventions of methods: +// (url broken into two lines) +// http://developer.apple.com/documentation/Cocoa/Conceptual/ +// MemoryMgmt/Tasks/MemoryManagementRules.html +// +// "You take ownership of an object if you create it using a method whose name +// begins with "alloc" or "new" or contains "copy" (for example, alloc, +// newObject, or mutableCopy), or if you send it a retain message. You are +// responsible for relinquishing ownership of objects you own using release +// or autorelease. Any other time you receive an object, you must +// not release it." +// + +static bool isWordEnd(char ch, char prev, char next) { + return ch == '\0' + || (islower(prev) && isupper(ch)) // xxxC + || (isupper(prev) && isupper(ch) && islower(next)) // XXCreate + || !isalpha(ch); +} + +static const char* parseWord(const char* s) { + char ch = *s, prev = '\0'; + assert(ch != '\0'); + char next = *(s+1); + while (!isWordEnd(ch, prev, next)) { + prev = ch; + ch = next; + next = *((++s)+1); + } + return s; +} + +cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S) { + IdentifierInfo *II = S.getIdentifierInfoForSlot(0); + + if (!II) + return NoConvention; + + const char *s = II->getNameStart(); + + // A method/function name may contain a prefix. We don't know it is there, + // however, until we encounter the first '_'. + bool InPossiblePrefix = true; + bool AtBeginning = true; + NamingConvention C = NoConvention; + + while (*s != '\0') { + // Skip '_'. + if (*s == '_') { + if (InPossiblePrefix) { + // If we already have a convention, return it. Otherwise, skip + // the prefix as if it wasn't there. + if (C != NoConvention) + break; + + InPossiblePrefix = false; + AtBeginning = true; + assert(C == NoConvention); + } + ++s; + continue; + } + + // Skip numbers, ':', etc. + if (!isalpha(*s)) { + ++s; + continue; + } + + const char *wordEnd = parseWord(s); + assert(wordEnd > s); + unsigned len = wordEnd - s; + + switch (len) { + default: + break; + case 3: + // Methods starting with 'new' follow the create rule. + if (AtBeginning && StringRef(s, len).equals_lower("new")) + C = CreateRule; + break; + case 4: + // Methods starting with 'alloc' or contain 'copy' follow the + // create rule + if (C == NoConvention && StringRef(s, len).equals_lower("copy")) + C = CreateRule; + else // Methods starting with 'init' follow the init rule. + if (AtBeginning && StringRef(s, len).equals_lower("init")) + C = InitRule; + break; + case 5: + if (AtBeginning && StringRef(s, len).equals_lower("alloc")) + C = CreateRule; + break; + } + + // If we aren't in the prefix and have a derived convention then just + // return it now. + if (!InPossiblePrefix && C != NoConvention) + return C; + + AtBeginning = false; + s = wordEnd; + } + + // We will get here if there wasn't more than one word + // after the prefix. + return C; +} |