[cfe-commits] r82166 - in /cfe/trunk: include/clang/Basic/ include/clang/Lex/ include/clang/Parse/ include/clang/Sema/ lib/Basic/ lib/Lex/ lib/Parse/ lib/Sema/ test/ test/CodeCompletion/ tools/clang-cc/

Douglas Gregor dgregor at apple.com
Thu Sep 17 14:32:04 PDT 2009


Author: dgregor
Date: Thu Sep 17 16:32:03 2009
New Revision: 82166

URL: http://llvm.org/viewvc/llvm-project?rev=82166&view=rev
Log:
Initial implementation of a code-completion interface in Clang. In
essence, code completion is triggered by a magic "code completion"
token produced by the lexer [*], which the parser recognizes at
certain points in the grammar. The parser then calls into the Action
object with the appropriate CodeCompletionXXX action.

Sema implements the CodeCompletionXXX callbacks by performing minimal
translation, then forwarding them to a CodeCompletionConsumer
subclass, which uses the results of semantic analysis to provide
code-completion results. At present, only a single, "printing" code
completion consumer is available, for regression testing and
debugging. However, the design is meant to permit other
code-completion consumers.

This initial commit contains two code-completion actions: one for
member access, e.g., "x." or "p->", and one for
nested-name-specifiers, e.g., "std::". More code-completion actions
will follow, along with improved gathering of code-completion results
for the various contexts.

[*] In the current -code-completion-dump testing/debugging mode, the
file is truncated at the completion point and EOF is translated into
"code completion".

Added:
    cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h   (with props)
    cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp   (with props)
    cfe/trunk/lib/Sema/SemaCodeComplete.cpp   (with props)
    cfe/trunk/test/CodeCompletion/
    cfe/trunk/test/CodeCompletion/member-access.c   (with props)
    cfe/trunk/test/CodeCompletion/member-access.cpp   (with props)
    cfe/trunk/test/CodeCompletion/nested-name-specifier.cpp   (with props)
Modified:
    cfe/trunk/include/clang/Basic/Diagnostic.h
    cfe/trunk/include/clang/Basic/TokenKinds.def
    cfe/trunk/include/clang/Lex/Lexer.h
    cfe/trunk/include/clang/Lex/Preprocessor.h
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/include/clang/Sema/ParseAST.h
    cfe/trunk/lib/Basic/Diagnostic.cpp
    cfe/trunk/lib/Lex/Lexer.cpp
    cfe/trunk/lib/Lex/Preprocessor.cpp
    cfe/trunk/lib/Parse/ParseExpr.cpp
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Sema/CMakeLists.txt
    cfe/trunk/lib/Sema/ParseAST.cpp
    cfe/trunk/lib/Sema/Sema.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/test/CMakeLists.txt
    cfe/trunk/tools/clang-cc/clang-cc.cpp

Modified: cfe/trunk/include/clang/Basic/Diagnostic.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Diagnostic.h?rev=82166&r1=82165&r2=82166&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/Diagnostic.h (original)
+++ cfe/trunk/include/clang/Basic/Diagnostic.h Thu Sep 17 16:32:03 2009
@@ -166,6 +166,7 @@
   bool IgnoreAllWarnings;        // Ignore all warnings: -w
   bool WarningsAsErrors;         // Treat warnings like errors:
   bool SuppressSystemWarnings;   // Suppress warnings in system headers.
+  bool SuppressAllDiagnostics;   // Suppress all diagnostics.
   ExtensionHandling ExtBehavior; // Map extensions onto warnings or errors?
   DiagnosticClient *Client;
 
@@ -245,6 +246,14 @@
   void setSuppressSystemWarnings(bool Val) { SuppressSystemWarnings = Val; }
   bool getSuppressSystemWarnings() const { return SuppressSystemWarnings; }
 
+  /// \brief Suppress all diagnostics, to silence the front end when we 
+  /// know that we don't want any more diagnostics to be passed along to the
+  /// client
+  void setSuppressAllDiagnostics(bool Val = true) { 
+    SuppressAllDiagnostics = Val; 
+  }
+  bool getSuppressAllDiagnostics() const { return SuppressAllDiagnostics; }
+  
   /// setExtensionHandlingBehavior - This controls whether otherwise-unmapped
   /// extension diagnostics are mapped onto ignore/warning/error.  This
   /// corresponds to the GCC -pedantic and -pedantic-errors option.

Modified: cfe/trunk/include/clang/Basic/TokenKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TokenKinds.def?rev=82166&r1=82165&r2=82166&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/TokenKinds.def (original)
+++ cfe/trunk/include/clang/Basic/TokenKinds.def Thu Sep 17 16:32:03 2009
@@ -92,6 +92,7 @@
 TOK(unknown)             // Not a token.
 TOK(eof)                 // End of file.
 TOK(eom)                 // End of macro (end of line inside a macro).
+TOK(code_completion)     // Code completion marker
 
 // C99 6.4.9: Comments.
 TOK(comment)             // Comment (only in -E -C[C] mode)

Modified: cfe/trunk/include/clang/Lex/Lexer.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Lexer.h?rev=82166&r1=82165&r2=82166&view=diff

==============================================================================
--- cfe/trunk/include/clang/Lex/Lexer.h (original)
+++ cfe/trunk/include/clang/Lex/Lexer.h Thu Sep 17 16:32:03 2009
@@ -39,7 +39,8 @@
   SourceLocation FileLoc;        // Location for start of file.
   LangOptions Features;          // Features enabled by this language (cache).
   bool Is_PragmaLexer;           // True if lexer for _Pragma handling.
-
+  bool IsEofCodeCompletion;      // True if EOF is treated as a code-completion.
+  
   //===--------------------------------------------------------------------===//
   // Context-specific lexing flags set by the preprocessor.
   //
@@ -178,6 +179,15 @@
     ExtendedTokenMode = Mode ? 1 : 0;
   }
 
+  /// \brief Specify that end-of-file is to be considered a code-completion
+  /// token.
+  ///
+  /// When in this mode, the end-of-file token will be immediately preceded
+  /// by a code-completion token.
+  void SetEofIsCodeCompletion() {
+    IsEofCodeCompletion = true;
+  }
+  
   const char *getBufferStart() const { return BufferStart; }
 
   /// ReadToEndOfLine - Read the rest of the current preprocessor line as an

Modified: cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=82166&r1=82165&r2=82166&view=diff

==============================================================================
--- cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/trunk/include/clang/Lex/Preprocessor.h Thu Sep 17 16:32:03 2009
@@ -92,6 +92,10 @@
   bool DisableMacroExpansion : 1;  // True if macro expansion is disabled.
   bool InMacroArgs : 1;            // True if parsing fn macro invocation args.
 
+  /// \brief True if the end-of-file of the main file should be treated as
+  /// a code-completion token.
+  bool IsMainFileEofCodeCompletion : 1;
+
   /// Identifiers - This is mapping/lookup information for all identifiers in
   /// the program, including program keywords.
   IdentifierTable Identifiers;
@@ -259,6 +263,12 @@
     Callbacks = C;
   }
 
+  /// \brief Note that, for the main source file, the end-of-file should be
+  /// treated as a code-completion token.
+  void SetMainFileEofCodeCompletion() {
+    IsMainFileEofCodeCompletion = true;
+  }
+  
   /// getMacroInfo - Given an identifier, return the MacroInfo it is #defined to
   /// or null if it isn't #define'd.
   MacroInfo *getMacroInfo(IdentifierInfo *II) const {

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=82166&r1=82165&r2=82166&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Thu Sep 17 16:32:03 2009
@@ -2185,6 +2185,49 @@
                                     SourceLocation AliasNameLoc) {
     return;
   }
+  
+  /// \name Code completion actions
+  ///
+  /// These actions are used to signal that a code-completion token has been
+  /// found at a point in the grammar where the Action implementation is
+  /// likely to be able to provide a list of possible completions, e.g.,
+  /// after the "." or "->" of a member access expression.
+  ///
+  //@{
+  
+  /// \brief Code completion for a member access expression.
+  ///
+  /// This code completion action is invoked when the code-completion token
+  /// is found after the "." or "->" of a member access expression.
+  ///
+  /// \param S the scope in which the member access expression occurs.
+  ///
+  /// \param Base the base expression (e.g., the x in "x.foo") of the member
+  /// access.
+  ///
+  /// \param OpLoc the location of the "." or "->" operator.
+  ///
+  /// \param IsArrow true when the operator is "->", false when it is ".".
+  virtual void CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *Base,
+                                               SourceLocation OpLoc,
+                                               bool IsArrow) {
+  }
+  
+  /// \brief Code completion for a C++ nested-name-specifier that precedes a
+  /// qualified-id of some form.
+  ///
+  /// This code completion action is invoked when the code-completion token
+  /// is found after the "::" of a nested-name-specifier.
+  ///
+  /// \param S the scope in which the nested-name-specifier occurs.
+  /// 
+  /// \param SS the scope specifier ending with "::".
+  ///
+  /// \parameter EnteringContext whether we're entering the context of this
+  /// scope specifier.
+  virtual void CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
+                                       bool EnteringContext) { }
+  //@}
 };
 
 /// MinimalAction - Minimal actions are used by light-weight clients of the

Added: cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h?rev=82166&view=auto

==============================================================================
--- cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h (added)
+++ cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h Thu Sep 17 16:32:03 2009
@@ -0,0 +1,183 @@
+//===---- CodeCompleteConsumer.h - Code Completion Interface ----*- 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 the CodeCompleteConsumer class.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_SEMA_CODECOMPLETECONSUMER_H
+#define LLVM_CLANG_SEMA_CODECOMPLETECONSUMER_H
+
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/Type.h"
+#include <list>
+#include <map>
+#include <vector>
+
+namespace llvm {
+class raw_ostream;
+}
+
+namespace clang {
+  
+class DeclContext;
+class NamedDecl;
+class Scope;
+class Sema;
+  
+/// \brief Abstract interface for a consumer of code-completion 
+/// information.
+class CodeCompleteConsumer {
+  /// \brief The semantic-analysis object to which this code-completion
+  /// consumer is attached.
+  Sema &SemaRef;
+  
+public:
+  /// \brief Captures a result of code completion.
+  struct Result {
+    /// \brief Describes the kind of result generated.
+    enum ResultKind {
+      RK_Declaration = 0, //< Refers to a declaration
+      RK_Keyword,        //< Refers to a keyword or symbol.
+    };
+    
+    /// \brief The kind of result stored here.
+    ResultKind Kind;
+    
+    union {
+      /// \brief When Kind == RK_Declaration, the declaration we are referring
+      /// to.
+      NamedDecl *Declaration;
+      
+      /// \brief When Kind == RK_Keyword, the string representing the keyword 
+      /// or symbol's spelling.
+      const char *Keyword;
+    };
+    
+    /// \brief Describes how good this result is, with zero being the best
+    /// result and progressively higher numbers representing poorer results.
+    unsigned Rank;
+    
+    /// \brief Whether this result is hidden by another name.
+    bool Hidden : 1;
+    
+    /// \brief Build a result that refers to a declaration.
+    Result(NamedDecl *Declaration, unsigned Rank)
+      : Kind(RK_Declaration), Declaration(Declaration), Rank(Rank), 
+        Hidden(false) { }
+    
+    /// \brief Build a result that refers to a keyword or symbol.
+    Result(const char *Keyword, unsigned Rank)
+      : Kind(RK_Keyword), Keyword(Keyword), Rank(Rank), Hidden(false) { }
+  };
+  
+  /// \brief A container of code-completion results.
+  class ResultSet {
+    /// \brief The actual results we have found.
+    std::vector<Result> Results;
+
+    /// \brief A mapping from declaration names to the declarations that have
+    /// this name within a particular scope and their index within the list of
+    /// results.
+    typedef std::multimap<DeclarationName, 
+                          std::pair<NamedDecl *, unsigned> > ShadowMap;
+    
+    /// \brief A list of shadow maps, which is used to model name hiding at
+    /// different levels of, e.g., the inheritance hierarchy.
+    std::list<ShadowMap> ShadowMaps;
+    
+  public:
+    typedef std::vector<Result>::iterator iterator;
+    iterator begin() { return Results.begin(); }
+    iterator end() { return Results.end(); }
+    
+    Result *data() { return Results.empty()? 0 : &Results.front(); }
+    unsigned size() const { return Results.size(); }
+    bool empty() const { return Results.empty(); }
+    
+    /// \brief Add a new result to this result set (if it isn't already in one
+    /// of the shadow maps), or replace an existing result (for, e.g., a 
+    /// redeclaration).
+    void MaybeAddResult(Result R);
+    
+    /// \brief Enter into a new scope.
+    void EnterNewScope();
+    
+    /// \brief Exit from the current scope.
+    void ExitScope();
+  };
+  
+  /// \brief Create a new code-completion consumer and registers it with
+  /// the given semantic-analysis object.
+  explicit CodeCompleteConsumer(Sema &S);
+  
+  /// \brief Deregisters and destroys this code-completion consumer.
+  virtual ~CodeCompleteConsumer();
+  
+  /// \brief Retrieve the semantic-analysis object to which this code-completion
+  /// consumer is attached.
+  Sema &getSema() const { return SemaRef; }
+  
+  /// \name Code-completion callbacks
+  //@{
+  
+  /// \brief Process the finalized code-completion results.
+  virtual void ProcessCodeCompleteResults(Result *Results, 
+                                          unsigned NumResults) { }
+  
+  /// \brief Code completion for a member access expression, e.g., "x->" or
+  /// "x.".
+  ///
+  /// \param S is the scope in which code-completion occurs.
+  ///
+  /// \param BaseType is the type whose members are being accessed.
+  ///
+  /// \param IsArrow whether this member referenced was written with an
+  /// arrow ("->") or a period (".").
+  virtual void CodeCompleteMemberReferenceExpr(Scope *S, QualType BaseType,
+                                               bool IsArrow);
+  
+  /// \brief Code completion for a qualified-id, e.g., "std::"
+  ///
+  /// \param S the scope in which the nested-name-specifier occurs.
+  ///
+  /// \param NNS the nested-name-specifier before the code-completion location.
+  ///
+  /// \param EnteringContext whether the parser will be entering the scope of
+  /// the qualified-id.
+  virtual void CodeCompleteQualifiedId(Scope *S, NestedNameSpecifier *NNS,
+                                       bool EnteringContext);
+  //@}
+  
+  /// \name Utility functions
+  //@{
+  unsigned CollectMemberResults(DeclContext *Ctx, unsigned InitialRank, 
+                                ResultSet &Results);
+  //@}
+};
+  
+/// \brief A simple code-completion consumer that prints the results it 
+/// receives in a simple format.
+class PrintingCodeCompleteConsumer : public CodeCompleteConsumer {
+  /// \brief The raw output stream.
+  llvm::raw_ostream &OS;
+  
+public:
+  /// \brief Create a new printing code-completion consumer that prints its
+  /// results to the given raw output stream.
+  PrintingCodeCompleteConsumer(Sema &S, llvm::raw_ostream &OS)
+    : CodeCompleteConsumer(S), OS(OS) { }
+  
+  /// \brief Prints the finalized code-completion results.
+  virtual void ProcessCodeCompleteResults(Result *Results, 
+                                          unsigned NumResults);
+};
+  
+} // end namespace clang
+
+#endif // LLVM_CLANG_SEMA_CODECOMPLETECONSUMER_H

Propchange: cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h

------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h

------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/include/clang/Sema/ParseAST.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ParseAST.h?rev=82166&r1=82165&r2=82166&view=diff

==============================================================================
--- cfe/trunk/include/clang/Sema/ParseAST.h (original)
+++ cfe/trunk/include/clang/Sema/ParseAST.h Thu Sep 17 16:32:03 2009
@@ -18,7 +18,9 @@
   class Preprocessor;
   class ASTConsumer;
   class ASTContext;
-
+  class CodeCompleteConsumer;
+  class Sema;
+  
   /// \brief Parse the entire file specified, notifying the ASTConsumer as
   /// the file is parsed.
   ///
@@ -30,7 +32,9 @@
   /// end-of-translation-unit wrapup will be performed.
   void ParseAST(Preprocessor &pp, ASTConsumer *C,
                 ASTContext &Ctx, bool PrintStats = false,
-                bool CompleteTranslationUnit = true);
+                bool CompleteTranslationUnit = true,
+            CodeCompleteConsumer *(CreateCodeCompleter)(Sema &, void *Data) = 0,
+                void *CreateCodeCompleterData = 0);
 
 }  // end namespace clang
 

Modified: cfe/trunk/lib/Basic/Diagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Diagnostic.cpp?rev=82166&r1=82165&r2=82166&view=diff

==============================================================================
--- cfe/trunk/lib/Basic/Diagnostic.cpp (original)
+++ cfe/trunk/lib/Basic/Diagnostic.cpp Thu Sep 17 16:32:03 2009
@@ -196,6 +196,7 @@
   IgnoreAllWarnings = false;
   WarningsAsErrors = false;
   SuppressSystemWarnings = false;
+  SuppressAllDiagnostics = false;
   ExtBehavior = Ext_Ignore;
 
   ErrorOccurred = false;
@@ -424,6 +425,9 @@
 bool Diagnostic::ProcessDiag() {
   DiagnosticInfo Info(this);
 
+  if (SuppressAllDiagnostics)
+    return false;
+  
   // Figure out the diagnostic level of this message.
   Diagnostic::Level DiagLevel;
   unsigned DiagID = Info.getID();

Modified: cfe/trunk/lib/Lex/Lexer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/Lexer.cpp?rev=82166&r1=82165&r2=82166&view=diff

==============================================================================
--- cfe/trunk/lib/Lex/Lexer.cpp (original)
+++ cfe/trunk/lib/Lex/Lexer.cpp Thu Sep 17 16:32:03 2009
@@ -70,7 +70,8 @@
          " to simplify lexing!");
 
   Is_PragmaLexer = false;
-
+  IsEofCodeCompletion = false;
+  
   // Start of the file is a start of line.
   IsAtStartOfLine = true;
 
@@ -1309,6 +1310,18 @@
     return true;  // Have a token.
   }
 
+  if (IsEofCodeCompletion) {
+    // We're at the end of the file, but we've been asked to conside the
+    // end of the file to be a code-completion token. Return the
+    // code-completion token.
+    Result.startToken();
+    FormTokenWithChars(Result, CurPtr, tok::code_completion);
+
+    // Only do the eof -> code_completion translation once.
+    IsEofCodeCompletion = false;
+    return true;
+  }
+  
   // If we are in raw mode, return this event as an EOF token.  Let the caller
   // that put us in raw mode handle the event.
   if (isLexingRawMode()) {

Modified: cfe/trunk/lib/Lex/Preprocessor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/Preprocessor.cpp?rev=82166&r1=82165&r2=82166&view=diff

==============================================================================
--- cfe/trunk/lib/Lex/Preprocessor.cpp (original)
+++ cfe/trunk/lib/Lex/Preprocessor.cpp Thu Sep 17 16:32:03 2009
@@ -71,6 +71,7 @@
   // Macro expansion is enabled.
   DisableMacroExpansion = false;
   InMacroArgs = false;
+  IsMainFileEofCodeCompletion = false;
   NumCachedTokenLexers = 0;
 
   CachedLexPos = 0;
@@ -368,6 +369,13 @@
   // Enter the main file source buffer.
   EnterSourceFile(MainFileID, 0);
 
+  if (IsMainFileEofCodeCompletion) {
+    // Tell our newly-created lexer that it should treat its end-of-file as
+    // a code-completion token.
+    IsMainFileEofCodeCompletion = false;
+    static_cast<Lexer *>(getCurrentFileLexer())->SetEofIsCodeCompletion();
+  }
+  
   // Tell the header info that the main file was entered.  If the file is later
   // #imported, it won't be re-entered.
   if (const FileEntry *FE = SourceMgr.getFileEntryForID(MainFileID))

Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=82166&r1=82165&r2=82166&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Thu Sep 17 16:32:03 2009
@@ -935,6 +935,14 @@
         ParseOptionalCXXScopeSpecifier(SS, ObjectType, false);
       }
 
+      if (Tok.is(tok::code_completion)) {
+        // Code completion for a member access expression.
+        Actions.CodeCompleteMemberReferenceExpr(CurScope, LHS.get(),
+                                                OpLoc, OpKind == tok::arrow);
+        
+        ConsumeToken();
+      }
+      
       if (Tok.is(tok::identifier)) {
         if (!LHS.isInvalid())
           LHS = Actions.ActOnMemberReferenceExpr(CurScope, move(LHS), OpLoc,

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=82166&r1=82165&r2=82166&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Thu Sep 17 16:32:03 2009
@@ -85,6 +85,13 @@
       // To implement this, we clear out the object type as soon as we've
       // seen a leading '::' or part of a nested-name-specifier.
       ObjectType = 0;
+      
+      if (Tok.is(tok::code_completion)) {
+        // Code completion for a nested-name-specifier, where the code
+        // code completion token follows the '::'.
+        Actions.CodeCompleteQualifiedId(CurScope, SS, EnteringContext);
+        ConsumeToken();
+      }
     }
 
     // nested-name-specifier:

Modified: cfe/trunk/lib/Sema/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/CMakeLists.txt?rev=82166&r1=82165&r2=82166&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/CMakeLists.txt (original)
+++ cfe/trunk/lib/Sema/CMakeLists.txt Thu Sep 17 16:32:03 2009
@@ -1,6 +1,7 @@
 set(LLVM_NO_RTTI 1)
 
 add_clang_library(clangSema
+  CodeCompleteConsumer.cpp
   IdentifierResolver.cpp
   JumpDiagnostics.cpp
   ParseAST.cpp
@@ -10,6 +11,7 @@
   SemaCXXCast.cpp
   SemaCXXScopeSpec.cpp
   SemaChecking.cpp
+  SemaCodeComplete.cpp
   SemaDecl.cpp
   SemaDeclAttr.cpp
   SemaDeclCXX.cpp

Added: cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp?rev=82166&view=auto

==============================================================================
--- cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp (added)
+++ cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp Thu Sep 17 16:32:03 2009
@@ -0,0 +1,314 @@
+//===---- CodeCompleteConsumer.h - Code Completion Interface ----*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file implements the CodeCompleteConsumer class.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "Sema.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <string.h>
+using namespace clang;
+
+CodeCompleteConsumer::CodeCompleteConsumer(Sema &S) : SemaRef(S) {
+  SemaRef.setCodeCompleteConsumer(this);
+}
+
+CodeCompleteConsumer::~CodeCompleteConsumer() {
+  SemaRef.setCodeCompleteConsumer(0);
+}
+
+void 
+CodeCompleteConsumer::CodeCompleteMemberReferenceExpr(Scope *S, 
+                                                      QualType BaseType,
+                                                      bool IsArrow) {
+  if (IsArrow) {
+    if (const PointerType *Ptr = BaseType->getAs<PointerType>())
+      BaseType = Ptr->getPointeeType();
+    else if (BaseType->isObjCObjectPointerType())
+    /*Do nothing*/ ;
+    else
+      return;
+  }
+  
+  ResultSet Results;
+  unsigned NextRank = 0;
+  
+  if (const RecordType *Record = BaseType->getAs<RecordType>()) {
+    NextRank = CollectMemberResults(Record->getDecl(), NextRank, Results);
+
+    if (getSema().getLangOptions().CPlusPlus) {
+      if (!Results.empty())
+        // The "template" keyword can follow "->" or "." in the grammar.
+        Results.MaybeAddResult(Result("template", NextRank++));
+
+      // FIXME: For C++, we also need to look into the current scope, since
+      // we could have the start of a nested-name-specifier.
+    }
+
+    // Hand off the results found for code completion.
+    ProcessCodeCompleteResults(Results.data(), Results.size());
+    
+    // We're done!
+    return;
+  }
+}
+
+void 
+CodeCompleteConsumer::CodeCompleteQualifiedId(Scope *S, 
+                                              NestedNameSpecifier *NNS,
+                                              bool EnteringContext) {
+  CXXScopeSpec SS;
+  SS.setScopeRep(NNS);
+  DeclContext *Ctx = getSema().computeDeclContext(SS, EnteringContext);
+  if (!Ctx)
+    return;
+  
+  ResultSet Results;
+  unsigned NextRank = CollectMemberResults(Ctx, 0, Results);
+  
+  // The "template" keyword can follow "::" in the grammar
+  if (!Results.empty())
+    Results.MaybeAddResult(Result("template", NextRank));
+  
+  ProcessCodeCompleteResults(Results.data(), Results.size());
+}
+
+void CodeCompleteConsumer::ResultSet::MaybeAddResult(Result R) {
+  if (R.Kind != Result::RK_Declaration) {
+    // For non-declaration results, just add the result.
+    Results.push_back(R);
+    return;
+  }
+  
+  // FIXME: Using declarations
+  
+  Decl *CanonDecl = R.Declaration->getCanonicalDecl();
+  unsigned IDNS = CanonDecl->getIdentifierNamespace();
+
+  // Friend declarations and declarations introduced due to friends are never
+  // added as results.
+  if (isa<FriendDecl>(CanonDecl) || 
+      (IDNS & (Decl::IDNS_OrdinaryFriend | Decl::IDNS_TagFriend)))
+    return;
+
+  ShadowMap &SMap = ShadowMaps.back();
+  ShadowMap::iterator I, IEnd;
+  for (llvm::tie(I, IEnd) = SMap.equal_range(R.Declaration->getDeclName());
+       I != IEnd; ++I) {
+    NamedDecl *ND = I->second.first;
+    unsigned Index = I->second.second;
+    if (ND->getCanonicalDecl() == CanonDecl) {
+      // This is a redeclaration. Always pick the newer declaration.
+      I->second.first = R.Declaration;
+      Results[Index].Declaration = R.Declaration;
+      
+      // Pick the best rank of the two.
+      Results[Index].Rank = std::min(Results[Index].Rank, R.Rank);
+      
+      // We're done.
+      return;
+    }
+  }
+  
+  // This is a new declaration in this scope. However, check whether this
+  // declaration name is hidden by a similarly-named declaration in an outer
+  // scope.
+  std::list<ShadowMap>::iterator SM, SMEnd = ShadowMaps.end();
+  --SMEnd;
+  for (SM = ShadowMaps.begin(); SM != SMEnd; ++SM) {
+    for (llvm::tie(I, IEnd) = SM->equal_range(R.Declaration->getDeclName());
+         I != IEnd; ++I) {
+      // A tag declaration does not hide a non-tag declaration.
+      if (I->second.first->getIdentifierNamespace() == Decl::IDNS_Tag &&
+          (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary | 
+                   Decl::IDNS_ObjCProtocol)))
+        continue;
+      
+      // Protocols are in distinct namespaces from everything else.
+      if (((I->second.first->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol)
+           || (IDNS & Decl::IDNS_ObjCProtocol)) &&
+          I->second.first->getIdentifierNamespace() != IDNS)
+        continue;
+      
+      // The newly-added result is hidden by an entry in the shadow map.
+      R.Hidden = true;
+      break;
+    }
+  }
+  
+  // Insert this result into the set of results and into the current shadow
+  // map.
+  SMap.insert(std::make_pair(R.Declaration->getDeclName(),
+                             std::make_pair(R.Declaration, Results.size())));
+  Results.push_back(R);
+}
+
+/// \brief Enter into a new scope.
+void CodeCompleteConsumer::ResultSet::EnterNewScope() {
+  ShadowMaps.push_back(ShadowMap());
+}
+
+/// \brief Exit from the current scope.
+void CodeCompleteConsumer::ResultSet::ExitScope() {
+  ShadowMaps.pop_back();
+}
+
+/// \brief Collect the results of searching for members within the given
+/// declaration context.
+///
+/// \param Ctx the declaration context from which we will gather results.
+///
+/// \param InitialRank the initial rank given to results in this tag
+/// declaration. Larger rank values will be used for, e.g., members found
+/// in base classes.
+///
+/// \param Results the result set that will be extended with any results
+/// found within this declaration context (and, for a C++ class, its bases).
+///
+/// \returns the next higher rank value, after considering all of the
+/// names within this declaration context.
+unsigned CodeCompleteConsumer::CollectMemberResults(DeclContext *Ctx, 
+                                                    unsigned InitialRank,
+                                                    ResultSet &Results) {
+  // Enumerate all of the results in this context.
+  Results.EnterNewScope();
+  for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx; 
+       CurCtx = CurCtx->getNextContext()) {
+    for (DeclContext::decl_iterator D = CurCtx->decls_begin(), 
+                                 DEnd = CurCtx->decls_end();
+         D != DEnd; ++D) {
+      if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) {
+        // FIXME: Apply a filter to the results
+        Results.MaybeAddResult(Result(ND, InitialRank));
+      }
+    }
+  }
+  
+  // Traverse the contexts of inherited classes.
+  unsigned NextRank = InitialRank;
+  if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) {
+    for (CXXRecordDecl::base_class_iterator B = Record->bases_begin(),
+                                         BEnd = Record->bases_end();
+         B != BEnd; ++B) {
+      QualType BaseType = B->getType();
+      
+      // Don't look into dependent bases, because name lookup can't look
+      // there anyway.
+      if (BaseType->isDependentType())
+        continue;
+      
+      const RecordType *Record = BaseType->getAs<RecordType>();
+      if (!Record)
+        continue;
+      
+      // FIXME: We should keep track of the virtual bases we visit, so 
+      // that we don't visit them more than once.
+      
+      // FIXME: It would be nice to be able to determine whether referencing
+      // a particular member would be ambiguous. For example, given
+      //
+      //   struct A { int member; };
+      //   struct B { int member; };
+      //   struct C : A, B { };
+      //
+      //   void f(C *c) { c->### }
+      // accessing 'member' would result in an ambiguity. However, code
+      // completion could be smart enough to qualify the member with the
+      // base class, e.g.,
+      //
+      //   c->B::member
+      //
+      // or
+      //
+      //   c->A::member
+      
+      // Collect results from this base class (and its bases).
+      NextRank = std::max(NextRank, 
+                          CollectMemberResults(Record->getDecl(), 
+                                               InitialRank + 1, 
+                                               Results));
+    }
+  }
+  
+  // FIXME: Look into base classes in Objective-C!
+
+  Results.ExitScope();
+  return NextRank;
+}
+
+namespace {
+  struct VISIBILITY_HIDDEN SortCodeCompleteResult {
+    typedef CodeCompleteConsumer::Result Result;
+    
+    bool operator()(const Result &X, const Result &Y) const {
+      // Sort first by rank.
+      if (X.Rank < Y.Rank)
+        return true;
+      else if (X.Rank > Y.Rank)
+        return false;
+      
+      // Result kinds are ordered by decreasing importance.
+      if (X.Kind < Y.Kind)
+        return true;
+      else if (X.Kind > Y.Kind)
+        return false;
+
+      // Non-hidden names precede hidden names.
+      if (X.Hidden != Y.Hidden)
+        return !X.Hidden;
+      
+      // Ordering depends on the kind of result.
+      switch (X.Kind) {
+      case Result::RK_Declaration:
+        // Order based on the declaration names.
+        return X.Declaration->getDeclName() < Y.Declaration->getDeclName();
+          
+      case Result::RK_Keyword:
+        return strcmp(X.Keyword, Y.Keyword) == -1;
+      }
+      
+      // If only our C++ compiler did control-flow warnings properly.
+      return false;
+    }
+  };
+}
+
+void 
+PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results, 
+                                                         unsigned NumResults) {
+  // Sort the results by rank/kind/etc.
+  std::stable_sort(Results, Results + NumResults, SortCodeCompleteResult());
+  
+  // Print the results.
+  for (unsigned I = 0; I != NumResults; ++I) {
+    switch (Results[I].Kind) {
+    case Result::RK_Declaration:
+      OS << Results[I].Declaration->getNameAsString() << " : " 
+         << Results[I].Rank;
+      if (Results[I].Hidden)
+        OS << " (Hidden)";
+      OS << '\n';
+      break;
+      
+    case Result::RK_Keyword:
+      OS << Results[I].Keyword << " : " << Results[I].Rank << '\n';
+      break;
+    }
+  }
+  
+  // Once we've printed the code-completion results, suppress remaining
+  // diagnostics.
+  // FIXME: Move this somewhere else!
+  getSema().PP.getDiagnostics().setSuppressAllDiagnostics();
+}

Propchange: cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp

------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp

------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/lib/Sema/ParseAST.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/ParseAST.cpp?rev=82166&r1=82165&r2=82166&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/ParseAST.cpp (original)
+++ cfe/trunk/lib/Sema/ParseAST.cpp Thu Sep 17 16:32:03 2009
@@ -13,6 +13,7 @@
 
 #include "clang/Sema/ParseAST.h"
 #include "Sema.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
 #include "clang/Sema/SemaConsumer.h"
 #include "clang/Sema/ExternalSemaSource.h"
 #include "clang/AST/ASTConsumer.h"
@@ -33,7 +34,9 @@
 ///
 void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
                      ASTContext &Ctx, bool PrintStats,
-                     bool CompleteTranslationUnit) {
+                     bool CompleteTranslationUnit,
+                CodeCompleteConsumer *(CreateCodeCompleter)(Sema &, void *Data),
+                     void *CreateCodeCompleterData) {
   // Collect global stats on Decls/Stmts (until we have a module streamer).
   if (PrintStats) {
     Decl::CollectingStats(true);
@@ -60,6 +63,10 @@
     External->StartTranslationUnit(Consumer);
   }
 
+  CodeCompleteConsumer *CodeCompleter = 0;
+  if (CreateCodeCompleter)
+    CodeCompleter = CreateCodeCompleter(S, CreateCodeCompleterData);
+  
   Parser::DeclGroupPtrTy ADecl;
 
   while (!P.ParseTopLevelDecl(ADecl)) {  // Not end of file.
@@ -78,6 +85,9 @@
 
   Consumer->HandleTranslationUnit(Ctx);
 
+  if (CreateCodeCompleter)
+    delete CodeCompleter;
+  
   if (PrintStats) {
     fprintf(stderr, "\nSTATISTICS:\n");
     P.getActions().PrintStats();

Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=82166&r1=82165&r2=82166&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Thu Sep 17 16:32:03 2009
@@ -191,9 +191,9 @@
            bool CompleteTranslationUnit)
   : LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer),
     Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
-    ExternalSource(0), CurContext(0), PreDeclaratorDC(0),
-    CurBlock(0), PackContext(0), IdResolver(pp.getLangOptions()),
-    StdNamespace(0), StdBadAlloc(0),
+    ExternalSource(0), CodeCompleter(0), CurContext(0), 
+    PreDeclaratorDC(0), CurBlock(0), PackContext(0), 
+    IdResolver(pp.getLangOptions()), StdNamespace(0), StdBadAlloc(0),
     GlobalNewDeleteDeclared(false), ExprEvalContext(PotentiallyEvaluated),
     CompleteTranslationUnit(CompleteTranslationUnit),
     NumSFINAEErrors(0), CurrentInstantiationScope(0) {

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=82166&r1=82165&r2=82166&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Thu Sep 17 16:32:03 2009
@@ -42,6 +42,7 @@
 namespace clang {
   class ASTContext;
   class ASTConsumer;
+  class CodeCompleteConsumer;
   class Preprocessor;
   class Decl;
   class DeclContext;
@@ -178,6 +179,9 @@
   /// \brief Source of additional semantic information.
   ExternalSemaSource *ExternalSource;
 
+  /// \brief Code-completion consumer.
+  CodeCompleteConsumer *CodeCompleter;
+
   /// CurContext - This is the current declaration context of parsing.
   DeclContext *CurContext;
 
@@ -3618,6 +3622,23 @@
 
     return T.getUnqualifiedType();
   }
+
+  /// \name Code completion
+  //@{
+private:
+  friend class CodeCompleteConsumer;
+  
+  void setCodeCompleteConsumer(CodeCompleteConsumer *CCC);
+  
+public:
+  virtual void CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *Base,
+                                               SourceLocation OpLoc,
+                                               bool IsArrow);
+  
+  virtual void CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
+                                       bool EnteringContext);
+  //@}
+  
   //===--------------------------------------------------------------------===//
   // Extra semantic analysis beyond the C type system
 private:

Added: cfe/trunk/lib/Sema/SemaCodeComplete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=82166&view=auto

==============================================================================
--- cfe/trunk/lib/Sema/SemaCodeComplete.cpp (added)
+++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp Thu Sep 17 16:32:03 2009
@@ -0,0 +1,45 @@
+//===---------------- SemaCodeComplete.cpp - Code Completion ----*- 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 the code-completion semantic actions.
+//
+//===----------------------------------------------------------------------===//
+#include "Sema.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+
+using namespace clang;
+
+/// \brief Set the code-completion consumer for semantic analysis.
+void Sema::setCodeCompleteConsumer(CodeCompleteConsumer *CCC) {
+  assert(((CodeCompleter != 0) != (CCC != 0)) && 
+         "Already set or cleared a code-completion consumer?");
+  CodeCompleter = CCC;
+}
+
+void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
+                                           SourceLocation OpLoc,
+                                           bool IsArrow) {
+  if (!BaseE || !CodeCompleter)
+    return;
+  
+  Expr *Base = static_cast<Expr *>(BaseE);
+  QualType BaseType = Base->getType();
+   
+  CodeCompleter->CodeCompleteMemberReferenceExpr(S, BaseType, IsArrow);
+}
+
+void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
+                                   bool EnteringContext) {
+  if (!SS.getScopeRep() || !CodeCompleter)
+    return;
+  
+  CodeCompleter->CodeCompleteQualifiedId(S, 
+                                      (NestedNameSpecifier *)SS.getScopeRep(),
+                                         EnteringContext);
+}

Propchange: cfe/trunk/lib/Sema/SemaCodeComplete.cpp

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/lib/Sema/SemaCodeComplete.cpp

------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/lib/Sema/SemaCodeComplete.cpp

------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/test/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CMakeLists.txt?rev=82166&r1=82165&r2=82166&view=diff

==============================================================================
--- cfe/trunk/test/CMakeLists.txt (original)
+++ cfe/trunk/test/CMakeLists.txt Thu Sep 17 16:32:03 2009
@@ -1,5 +1,6 @@
 set(CLANG_TEST_DIRECTORIES
   "Analysis"
+  "CodeCompletion"
   "CodeGen"
   "CodeGenCXX"
   "CodeGenObjC"

Added: cfe/trunk/test/CodeCompletion/member-access.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeCompletion/member-access.c?rev=82166&view=auto

==============================================================================
--- cfe/trunk/test/CodeCompletion/member-access.c (added)
+++ cfe/trunk/test/CodeCompletion/member-access.c Thu Sep 17 16:32:03 2009
@@ -0,0 +1,13 @@
+// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
+// RUN: true
+struct Point {
+  float x;
+  float y;
+  float z;
+};
+
+void test(struct Point *p) {
+  // CHECK-CC1: x
+  // CHECK-CC1: y
+  // CHECK-CC1: z
+  p->
\ No newline at end of file

Propchange: cfe/trunk/test/CodeCompletion/member-access.c

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/CodeCompletion/member-access.c

------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/CodeCompletion/member-access.c

------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/CodeCompletion/member-access.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeCompletion/member-access.cpp?rev=82166&view=auto

==============================================================================
--- cfe/trunk/test/CodeCompletion/member-access.cpp (added)
+++ cfe/trunk/test/CodeCompletion/member-access.cpp Thu Sep 17 16:32:03 2009
@@ -0,0 +1,42 @@
+// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
+// RUN: true
+
+struct Base1 {
+  int member1;
+  float member2;
+};
+
+struct Base2 {
+  int member1;
+  double member3;
+  void memfun1(int);
+};
+
+struct Base3 : Base1, Base2 {
+  void memfun1(float);
+  void memfun1(double);
+  void memfun2(int);
+};
+
+struct Derived : Base3 {
+  int member4;
+  int memfun3(int);
+};
+
+class Proxy {
+public:
+  Derived *operator->() const;
+};
+
+void test(const Proxy &p) {
+  // CHECK-CC1: member4 : 0
+  // CHECK-CC1: memfun3 : 0
+  // CHECK-CC1: memfun1 : 1
+  // CHECK-CC1: memfun1 : 1
+  // CHECK-CC1: memfun2 : 1
+  // CHECK-CC1: member1 : 2
+  // CHECK-CC1: member1 : 2
+  // CHECK-CC1: member2 : 2
+  // CHECK-CC1: member3 : 2
+  // CHECK-CC1: memfun1 : 2 (Hidden)
+  p->
\ No newline at end of file

Propchange: cfe/trunk/test/CodeCompletion/member-access.cpp

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/CodeCompletion/member-access.cpp

------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/CodeCompletion/member-access.cpp

------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/CodeCompletion/nested-name-specifier.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeCompletion/nested-name-specifier.cpp?rev=82166&view=auto

==============================================================================
--- cfe/trunk/test/CodeCompletion/nested-name-specifier.cpp (added)
+++ cfe/trunk/test/CodeCompletion/nested-name-specifier.cpp Thu Sep 17 16:32:03 2009
@@ -0,0 +1,19 @@
+// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
+// RUN: true
+
+namespace N {
+  struct A { };
+  namespace M { 
+    struct C { };
+  };
+}
+
+namespace N {
+  struct B { };
+}
+
+// CHECK-CC1: A : 0
+// CHECK-CC1: B : 0
+// CHECK-CC1: M : 0
+// CHECK-CC1: template : 0
+N::
\ No newline at end of file

Propchange: cfe/trunk/test/CodeCompletion/nested-name-specifier.cpp

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/CodeCompletion/nested-name-specifier.cpp

------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/CodeCompletion/nested-name-specifier.cpp

------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/tools/clang-cc/clang-cc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-cc/clang-cc.cpp?rev=82166&r1=82165&r2=82166&view=diff

==============================================================================
--- cfe/trunk/tools/clang-cc/clang-cc.cpp (original)
+++ cfe/trunk/tools/clang-cc/clang-cc.cpp Thu Sep 17 16:32:03 2009
@@ -38,6 +38,7 @@
 #include "clang/Frontend/Utils.h"
 #include "clang/Analysis/PathDiagnostic.h"
 #include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
 #include "clang/Sema/ParseAST.h"
 #include "clang/Sema/SemaDiagnostic.h"
 #include "clang/AST/ASTConsumer.h"
@@ -213,6 +214,17 @@
  llvm::cl::desc("Specify output file"));
 
 
+static llvm::cl::opt<int>
+DumpCodeCompletion("code-completion-dump",
+                   llvm::cl::value_desc("N"),
+                   llvm::cl::desc("Dump code-completion information at $$N$$"));
+
+/// \brief Buld a new code-completion consumer that prints the results of
+/// code completion to standard output.
+static CodeCompleteConsumer *BuildPrintingCodeCompleter(Sema &S, void *) {
+  return new PrintingCodeCompleteConsumer(S, llvm::outs());
+}
+
 //===----------------------------------------------------------------------===//
 // PTH.
 //===----------------------------------------------------------------------===//
@@ -2046,12 +2058,29 @@
     if (InitializeSourceManager(PP, InFile))
       return;
   }
-
-
+  
   // If we have an ASTConsumer, run the parser with it.
-  if (Consumer)
+  if (Consumer) {
+    CodeCompleteConsumer *(*CreateCodeCompleter)(Sema &, void *) = 0;
+    void *CreateCodeCompleterData = 0;
+    
+    if (DumpCodeCompletion) {
+      // To dump code-completion information, we chop off the file at the
+      // location of the string $$N$$, where N is the value provided to
+      // -code-completion-dump, and then tell the lexer to return a 
+      // code-completion token before it hits the end of the file.
+      // FIXME: Find $$N$$ in the main file buffer
+      
+      PP.SetMainFileEofCodeCompletion();
+      
+      // Set up the creation routine for code-completion.
+      CreateCodeCompleter = BuildPrintingCodeCompleter;
+    }
+
     ParseAST(PP, Consumer.get(), *ContextOwner.get(), Stats,
-             CompleteTranslationUnit);
+             CompleteTranslationUnit,
+             CreateCodeCompleter, CreateCodeCompleterData);
+  }
 
   if (PA == RunPreprocessorOnly) {    // Just lex as fast as we can, no output.
     llvm::TimeRegion Timer(ClangFrontendTimer);





More information about the cfe-commits mailing list