aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2012-10-12 21:15:50 +0000
committerDouglas Gregor <dgregor@apple.com>2012-10-12 21:15:50 +0000
commit8b48e087bc0e022703d235fa6382551cfaa57ae6 (patch)
tree08634fac40836c0b5bbffc9183d0fe0d1d1cd06a
parent8b799f332d4d00798491f45cc14d47ff97e052c7 (diff)
Sanitize the names of modules determined based on the names of headers
or directories, to make sure that they are identifiers that are not keywords in any dialect. Fixes <rdar://problem/12489495>. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@165821 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Lex/ModuleMap.cpp73
-rw-r--r--test/Modules/Inputs/normal-module-map/nested_umbrella/1.h1
-rw-r--r--test/Modules/Inputs/normal-module-map/nested_umbrella/a-extras.h1
-rw-r--r--test/Modules/normal-module-map.cpp10
4 files changed, 79 insertions, 6 deletions
diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp
index a0caf03e77..514f03636e 100644
--- a/lib/Lex/ModuleMap.cpp
+++ b/lib/Lex/ModuleMap.cpp
@@ -97,6 +97,54 @@ void ModuleMap::setTarget(const TargetInfo &Target) {
this->Target = &Target;
}
+/// \brief "Sanitize" a filename so that it can be used as an identifier.
+static StringRef sanitizeFilenameAsIdentifier(StringRef Name,
+ SmallVectorImpl<char> &Buffer) {
+ if (Name.empty())
+ return Name;
+
+ // Check whether the filename is already an identifier; this is the common
+ // case.
+ bool isIdentifier = true;
+ for (unsigned I = 0, N = Name.size(); I != N; ++I) {
+ if (isalpha(Name[I]) || Name[I] == '_' || (isdigit(Name[I]) && I > 0))
+ continue;
+
+ isIdentifier = false;
+ break;
+ }
+
+ if (!isIdentifier) {
+ // If we don't already have something with the form of an identifier,
+ // create a buffer with the sanitized name.
+ Buffer.clear();
+ if (isdigit(Name[0]))
+ Buffer.push_back('_');
+ Buffer.reserve(Buffer.size() + Name.size());
+ for (unsigned I = 0, N = Name.size(); I != N; ++I) {
+ if (isalnum(Name[I]) || isspace(Name[I]))
+ Buffer.push_back(Name[I]);
+ else
+ Buffer.push_back('_');
+ }
+
+ Name = StringRef(Buffer.data(), Buffer.size());
+ }
+
+ while (llvm::StringSwitch<bool>(Name)
+#define KEYWORD(Keyword,Conditions) .Case(#Keyword, true)
+#define ALIAS(Keyword, AliasOf, Conditions) .Case(Keyword, true)
+#include "clang/Basic/TokenKinds.def"
+ .Default(false)) {
+ if (Name.data() != Buffer.data())
+ Buffer.append(Name.begin(), Name.end());
+ Buffer.push_back('_');
+ Name = StringRef(Buffer.data(), Buffer.size());
+ }
+
+ return Name;
+}
+
Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
llvm::DenseMap<const FileEntry *, Module *>::iterator Known
= Headers.find(File);
@@ -135,7 +183,10 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
for (unsigned I = SkippedDirs.size(); I != 0; --I) {
// Find or create the module that corresponds to this directory name.
- StringRef Name = llvm::sys::path::stem(SkippedDirs[I-1]->getName());
+ SmallString<32> NameBuf;
+ StringRef Name = sanitizeFilenameAsIdentifier(
+ llvm::sys::path::stem(SkippedDirs[I-1]->getName()),
+ NameBuf);
Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
Explicit).first;
@@ -149,7 +200,9 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
}
// Infer a submodule with the same name as this header file.
- StringRef Name = llvm::sys::path::stem(File->getName());
+ SmallString<32> NameBuf;
+ StringRef Name = sanitizeFilenameAsIdentifier(
+ llvm::sys::path::stem(File->getName()), NameBuf);
Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
Explicit).first;
Result->TopHeaders.insert(File);
@@ -218,7 +271,10 @@ bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) {
if (UmbrellaModule->InferSubmodules) {
for (unsigned I = SkippedDirs.size(); I != 0; --I) {
// Find or create the module that corresponds to this directory name.
- StringRef Name = llvm::sys::path::stem(SkippedDirs[I-1]->getName());
+ SmallString<32> NameBuf;
+ StringRef Name = sanitizeFilenameAsIdentifier(
+ llvm::sys::path::stem(SkippedDirs[I-1]->getName()),
+ NameBuf);
Found = lookupModuleQualified(Name, Found);
if (!Found)
return false;
@@ -227,7 +283,10 @@ bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) {
}
// Infer a submodule with the same name as this header file.
- StringRef Name = llvm::sys::path::stem(Header->getName());
+ SmallString<32> NameBuf;
+ StringRef Name = sanitizeFilenameAsIdentifier(
+ llvm::sys::path::stem(Header->getName()),
+ NameBuf);
Found = lookupModuleQualified(Name, Found);
if (!Found)
return false;
@@ -377,8 +436,10 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
#endif
// FIXME: Do we want to warn about subframeworks without umbrella headers?
- inferFrameworkModule(llvm::sys::path::stem(Dir->path()), SubframeworkDir,
- IsSystem, Result);
+ SmallString<32> NameBuf;
+ inferFrameworkModule(sanitizeFilenameAsIdentifier(
+ llvm::sys::path::stem(Dir->path()), NameBuf),
+ SubframeworkDir, IsSystem, Result);
}
}
diff --git a/test/Modules/Inputs/normal-module-map/nested_umbrella/1.h b/test/Modules/Inputs/normal-module-map/nested_umbrella/1.h
new file mode 100644
index 0000000000..e8a3e6340d
--- /dev/null
+++ b/test/Modules/Inputs/normal-module-map/nested_umbrella/1.h
@@ -0,0 +1 @@
+int one;
diff --git a/test/Modules/Inputs/normal-module-map/nested_umbrella/a-extras.h b/test/Modules/Inputs/normal-module-map/nested_umbrella/a-extras.h
new file mode 100644
index 0000000000..91522aa1a9
--- /dev/null
+++ b/test/Modules/Inputs/normal-module-map/nested_umbrella/a-extras.h
@@ -0,0 +1 @@
+int extra_a;
diff --git a/test/Modules/normal-module-map.cpp b/test/Modules/normal-module-map.cpp
index 7cd448235d..07ca5ed933 100644
--- a/test/Modules/normal-module-map.cpp
+++ b/test/Modules/normal-module-map.cpp
@@ -33,3 +33,13 @@ int testNestedUmbrellaBFail() {
int testNestedUmbrellaB() {
return nested_umbrella_b;
}
+
+@__experimental_modules_import nested_umbrella.a_extras;
+
+@__experimental_modules_import nested_umbrella._1;
+
+@__experimental_modules_import nested_umbrella.decltype_;
+
+int testSanitizedName() {
+ return extra_a + one + decltype_val;
+}