diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:04:05 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:04:05 +0000 |
| commit | 676fbe8105eeb6ff4bb2ed261cb212fcfdbe7b63 (patch) | |
| tree | 02a1ac369cb734d0abfa5000dd86e5b7797e6a74 /lib/Tooling/Core | |
| parent | c7e70c433efc6953dc3888b9fbf9f3512d7da2b0 (diff) | |
Notes
Diffstat (limited to 'lib/Tooling/Core')
| -rw-r--r-- | lib/Tooling/Core/Diagnostic.cpp | 9 | ||||
| -rw-r--r-- | lib/Tooling/Core/Lookup.cpp | 44 | ||||
| -rw-r--r-- | lib/Tooling/Core/Replacement.cpp | 17 |
3 files changed, 57 insertions, 13 deletions
diff --git a/lib/Tooling/Core/Diagnostic.cpp b/lib/Tooling/Core/Diagnostic.cpp index 9e4833f2eff4..e3a33d9a3755 100644 --- a/lib/Tooling/Core/Diagnostic.cpp +++ b/lib/Tooling/Core/Diagnostic.cpp @@ -23,10 +23,15 @@ DiagnosticMessage::DiagnosticMessage(llvm::StringRef Message) DiagnosticMessage::DiagnosticMessage(llvm::StringRef Message, const SourceManager &Sources, SourceLocation Loc) - : Message(Message) { + : Message(Message), FileOffset(0) { assert(Loc.isValid() && Loc.isFileID()); FilePath = Sources.getFilename(Loc); - FileOffset = Sources.getFileOffset(Loc); + + // Don't store offset in the scratch space. It doesn't tell anything to the + // user. Moreover, it depends on the history of macro expansions and thus + // prevents deduplication of warnings in headers. + if (!FilePath.empty()) + FileOffset = Sources.getFileOffset(Loc); } Diagnostic::Diagnostic(llvm::StringRef DiagnosticName, diff --git a/lib/Tooling/Core/Lookup.cpp b/lib/Tooling/Core/Lookup.cpp index 6edf61b8050d..cc448d144e2c 100644 --- a/lib/Tooling/Core/Lookup.cpp +++ b/lib/Tooling/Core/Lookup.cpp @@ -14,6 +14,7 @@ #include "clang/Tooling/Core/Lookup.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclarationName.h" using namespace clang; using namespace clang::tooling; @@ -114,6 +115,37 @@ static bool isFullyQualified(const NestedNameSpecifier *NNS) { return false; } +// Returns true if spelling symbol \p QName as \p Spelling in \p UseContext is +// ambiguous. For example, if QName is "::y::bar" and the spelling is "y::bar" +// in `UseContext` "a" that contains a nested namespace "a::y", then "y::bar" +// can be resolved to ::a::y::bar, which can cause compile error. +// FIXME: consider using namespaces. +static bool isAmbiguousNameInScope(StringRef Spelling, StringRef QName, + const DeclContext &UseContext) { + assert(QName.startswith("::")); + if (Spelling.startswith("::")) + return false; + + // Lookup the first component of Spelling in all enclosing namespaces and + // check if there is any existing symbols with the same name but in different + // scope. + StringRef Head = Spelling.split("::").first; + + llvm::SmallVector<const NamespaceDecl *, 4> UseNamespaces = + getAllNamedNamespaces(&UseContext); + auto &AST = UseContext.getParentASTContext(); + StringRef TrimmedQName = QName.substr(2); + for (const auto *NS : UseNamespaces) { + auto LookupRes = NS->lookup(DeclarationName(&AST.Idents.get(Head))); + if (!LookupRes.empty()) { + for (const NamedDecl *Res : LookupRes) + if (!TrimmedQName.startswith(Res->getQualifiedNameAsString())) + return true; + } + } + return false; +} + std::string tooling::replaceNestedName(const NestedNameSpecifier *Use, const DeclContext *UseContext, const NamedDecl *FromDecl, @@ -146,6 +178,14 @@ std::string tooling::replaceNestedName(const NestedNameSpecifier *Use, // figure out how good a namespace match we have with our destination type. // We work backwards (from most specific possible namespace to least // specific). - return getBestNamespaceSubstr(UseContext, ReplacementString, - isFullyQualified(Use)); + StringRef Suggested = getBestNamespaceSubstr(UseContext, ReplacementString, + isFullyQualified(Use)); + // Use the fully qualified name if the suggested name is ambiguous. + // FIXME: consider re-shortening the name until the name is not ambiguous. We + // are not doing this because ambiguity is pretty bad and we should not try to + // be clever in handling such cases. Making this noticeable to users seems to + // be a better option. + return isAmbiguousNameInScope(Suggested, ReplacementString, *UseContext) + ? ReplacementString + : Suggested; } diff --git a/lib/Tooling/Core/Replacement.cpp b/lib/Tooling/Core/Replacement.cpp index 67e2dcfd73c1..3b7e39814afa 100644 --- a/lib/Tooling/Core/Replacement.cpp +++ b/lib/Tooling/Core/Replacement.cpp @@ -19,7 +19,6 @@ #include "clang/Basic/FileSystemOptions.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" -#include "clang/Basic/VirtualFileSystem.h" #include "clang/Lex/Lexer.h" #include "clang/Rewrite/Core/RewriteBuffer.h" #include "clang/Rewrite/Core/Rewriter.h" @@ -29,6 +28,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cassert> @@ -483,12 +483,11 @@ Replacements Replacements::merge(const Replacements &ReplacesToMerge) const { // Returns a set of non-overlapping and sorted ranges that is equivalent to // \p Ranges. static std::vector<Range> combineAndSortRanges(std::vector<Range> Ranges) { - llvm::sort(Ranges.begin(), Ranges.end(), - [](const Range &LHS, const Range &RHS) { - if (LHS.getOffset() != RHS.getOffset()) - return LHS.getOffset() < RHS.getOffset(); - return LHS.getLength() < RHS.getLength(); - }); + llvm::sort(Ranges, [](const Range &LHS, const Range &RHS) { + if (LHS.getOffset() != RHS.getOffset()) + return LHS.getOffset() < RHS.getOffset(); + return LHS.getLength() < RHS.getLength(); + }); std::vector<Range> Result; for (const auto &R : Ranges) { if (Result.empty() || @@ -584,8 +583,8 @@ llvm::Expected<std::string> applyAllReplacements(StringRef Code, if (Replaces.empty()) return Code.str(); - IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem( - new vfs::InMemoryFileSystem); + IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( + new llvm::vfs::InMemoryFileSystem); FileManager Files(FileSystemOptions(), InMemoryFileSystem); DiagnosticsEngine Diagnostics( IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), |
