From 0fe6d45e626b9b51ea5b69631d9e35c8eb651fb5 Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Wed, 25 Sep 2013 01:35:36 +0000 Subject: [PATCH] [IDE] Introduce semantic annotation functionality and test. Swift SVN r8618 --- include/swift/IDE/SemanticSourceEntity.h | 54 +++++++++ lib/IDE/CMakeLists.txt | 1 + lib/IDE/SemanticSourceEntity.cpp | 134 +++++++++++++++++++++++ test/IDE/annotation.swift | 63 +++++++++++ 4 files changed, 252 insertions(+) create mode 100644 include/swift/IDE/SemanticSourceEntity.h create mode 100644 lib/IDE/SemanticSourceEntity.cpp create mode 100644 test/IDE/annotation.swift diff --git a/include/swift/IDE/SemanticSourceEntity.h b/include/swift/IDE/SemanticSourceEntity.h new file mode 100644 index 00000000000..49a382e7d81 --- /dev/null +++ b/include/swift/IDE/SemanticSourceEntity.h @@ -0,0 +1,54 @@ +//===- SemanticSourceEntity.h - Routines for semantic source info ---------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_IDE_SEMANTIC_SOURCE_ENTITY_H +#define SWIFT_IDE_SEMANTIC_SOURCE_ENTITY_H + +#include "swift/Basic/SourceLoc.h" +#include + +namespace swift { + class Decl; + class ValueDecl; + +namespace ide { + +struct SemanticSourceEntity { + CharSourceRange Range; + ValueDecl *Dcl; + bool IsRef; +}; + +/// A function receiving SemanticSourceEntity objects. +/// \returns true to continue receiving the next object, false to stop. +typedef std::function + SemanticEntityReceiverFn; + +/// Walks the provided declarations and passes SemanticSourceEntities to the +/// \c Receiver. +/// +/// The entities are given in source-order, as long as the \c Decls array is +/// already in source-order. +/// +/// \param Decls the array of declarations to traverse. +/// +/// \param Receiver the function receiving the entities. +/// +/// \returns true if all the entities were passed to the receiver, false if +/// the receiver stopped by returning false. +bool findSemanticSourceEntities(ArrayRef Decls, + SemanticEntityReceiverFn Receiver); + +} // namespace ide +} // namespace swift + +#endif diff --git a/lib/IDE/CMakeLists.txt b/lib/IDE/CMakeLists.txt index 2b788880d9e..36c04593e34 100644 --- a/lib/IDE/CMakeLists.txt +++ b/lib/IDE/CMakeLists.txt @@ -1,6 +1,7 @@ add_swift_library(swiftIDE CodeCompletion.cpp REPLCodeCompletion.cpp + SemanticSourceEntity.cpp SyntaxColoring.cpp DEPENDS swiftAST swiftParse swiftSema swiftClangImporter) diff --git a/lib/IDE/SemanticSourceEntity.cpp b/lib/IDE/SemanticSourceEntity.cpp new file mode 100644 index 00000000000..a151ef92fd8 --- /dev/null +++ b/lib/IDE/SemanticSourceEntity.cpp @@ -0,0 +1,134 @@ +//===- SemanticSourceEntity.cpp - Routines for semantic source info -------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "swift/IDE/SemanticSourceEntity.h" +#include "swift/AST/ASTWalker.h" +#include "swift/AST/Decl.h" +#include "swift/AST/Expr.h" +#include "swift/AST/TypeRepr.h" +#include "swift/AST/Types.h" + +using namespace swift; +using namespace ide; + +namespace { + +class SemaAnnotator : public ASTWalker { + SemanticEntityReceiverFn Receiver; + bool Cancelled = false; + +public: + explicit SemaAnnotator(SemanticEntityReceiverFn Receiver) + : Receiver(std::move(Receiver)) { } + + bool isDone() const { return Cancelled; } + +private: + bool walkToDeclPre(Decl *D) override; + std::pair walkToExprPre(Expr *E) override; + bool walkToTypeReprPre(TypeRepr *T) override; + + bool walkToDeclPost(Decl *D) override; + bool walkToTypeReprPost(TypeRepr *T) override; + + bool passToReceiver(ValueDecl *D, SourceLoc Loc, bool IsRef); +}; + +} + +bool SemaAnnotator::walkToDeclPre(Decl *D) { + if (D->isImplicit()) + return false; + + if (ValueDecl *VD = dyn_cast(D)) + return passToReceiver(VD, VD->getNameLoc(), /*IsRef=*/false); + + return true; +} + +bool SemaAnnotator::walkToDeclPost(Decl *D) { + if (isDone()) + return false; + return true; +} + +std::pair SemaAnnotator::walkToExprPre(Expr *E) { + if (isDone()) + return { false, nullptr }; + + if (E->isImplicit()) + return { true, E }; + + if (DeclRefExpr *DRE = dyn_cast(E)) { + if (!passToReceiver(DRE->getDecl(), E->getLoc(), /*IsRef=*/true)) + return { false, nullptr }; + } else if (MemberRefExpr *MRE = dyn_cast(E)) { + if (!passToReceiver(MRE->getMember().getDecl(), E->getLoc(), /*IsRef=*/true)) + return { false, nullptr }; + + } else if (BinaryExpr *BinE = dyn_cast(E)) { + // Visit in source order. + BinE->getArg()->getElement(0)->walk(*this); + BinE->getFn()->walk(*this); + BinE->getArg()->getElement(1)->walk(*this); + + // We already visited the children. + return { false, E }; + } + + return { true, E }; +} + +bool SemaAnnotator::walkToTypeReprPre(TypeRepr *T) { + if (IdentTypeRepr *IdT = dyn_cast(T)) { + for (auto &Comp : IdT->Components) { + if (ValueDecl *VD = Comp.getBoundDecl()) + return passToReceiver(VD, Comp.getIdLoc(), /*IsRef=*/true); + if (Type Ty = Comp.getBoundType()) { + if (NameAliasType *NAT = dyn_cast(Ty.getPointer())) { + return passToReceiver(NAT->getDecl(), Comp.getIdLoc(),/*IsRef=*/true); + } else if (NominalTypeDecl *NTD = Ty->getAnyNominal()) { + return passToReceiver(NTD, Comp.getIdLoc(), /*IsRef=*/true); + } + } + } + } + return true; +} + +bool SemaAnnotator::walkToTypeReprPost(TypeRepr *T) { + if (isDone()) + return false; + return true; +} + +bool SemaAnnotator::passToReceiver(ValueDecl *D, SourceLoc Loc, bool IsRef) { + CharSourceRange Range = CharSourceRange(Loc, D->getName().getLength()); + bool Continue = Receiver({ Range, D, IsRef }); + if (!Continue) + Cancelled = true; + return Continue; +} + +bool ide::findSemanticSourceEntities( + ArrayRef Decls, + std::function Receiver) { + + SemaAnnotator Annotator(Receiver); + for (Decl *D : Decls) { + D->walk(Annotator); + if (Annotator.isDone()) + return false; + } + + return true; +} diff --git a/test/IDE/annotation.swift b/test/IDE/annotation.swift new file mode 100644 index 00000000000..1a6bda0662c --- /dev/null +++ b/test/IDE/annotation.swift @@ -0,0 +1,63 @@ +// RUN: %swift-ide-test -annotate -source-filename %s | FileCheck %s + +// CHECK: struct S { +// CHECK: var x : Int +// CHECK: var y : swift.Int +// CHECK: } +struct S { + var x : Int + var y : swift.Int +} + +// CHECK: class MyCls { +// CHECK: var www : Int +// CHECK: func foo(x : Int) {} +// CHECK: } +class MyCls { + var www : Int + func foo(x : Int) {} +} + +// CHECK: func foo(n : Float) -> Int { +// CHECK: var q = MyCls() +// CHECK: var ee = "yoo"; +// CHECK: return 100009 +// CHECK: } +func foo(n : Float) -> Int { + var q = MyCls() + var ee = "yoo"; + return 100009 +} + +// CHECK: protocol Prot { +// CHECK: typealias Blarg +// CHECK: func protMeth(x: Int) +// CHECK: } +protocol Prot { + typealias Blarg + func protMeth(x: Int) +} +// CHECK: protocol Prot2 {} +protocol Prot2 {} + +// CHECK: class SubCls : MyCls, Prot { +// CHECK: typealias Blarg = Prot2 +// CHECK: func protMeth(x: Int) {} +// CHECK: } +class SubCls : MyCls, Prot { + typealias Blarg = Prot2 + func protMeth(x: Int) {} +} + +// CHECK: func genFn(p : T) -> Int {} +func genFn(p : T) -> Int {} + +// FIXME: Constructors. +func test(x: Int) { + genFn(SubCls()) + "This is string \(genFn({(a:Int) in SubCls()}(x))) interpolation" +} + +func bar(x: Int) -> (Int, Float) { + foo(Float()) +}