Init TagsExtension Module, for extending cling to provide interactive hints

AutoloadCallback: Implementing InterpreterCallbacks to attach the module to cling
   The main focus is on overriding LookupObject so that the information about
   lookup failures are obtained from clang.
   The type of the name is not taken into consideration for now.

TagManager: To manage and lookup information from various sorts of tag files.
   Currently a TagManager object is owned by the callback system.
   This may change in future.

Wrapper: As a base class for handling particular types of tagfiles.
   The TagManager maintains a container of Wrappers.

CtagsFileWrapper: Implementing a wrapper for ctags.
   This class is responsible for generating a tagfile from a given path or list of files.
   It also performs lookups in the file generated by it.

And a few simple file system utils to complement llvm::sys::fs and path utilities
This commit is contained in:
manasij7479 2014-05-24 14:21:02 +02:00 committed by sftnight
parent 2875e4d3e4
commit 024b16df11
31 changed files with 4185 additions and 3 deletions

101
#Makefile# Normal file
View File

@ -0,0 +1,101 @@
##===- Makefile --------------------------------------------*- Makefile -*-===##
#
# The Cling Interpreter
#
# This file is dual-licensed: you can choose to license it under the University
# of Illinois Open Source License or the GNU Lesser General Public License. See
# LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
# If CLING_LEVEL is not set, then we are the top-level Makefile. Otherwise, we
# are being included from a subdirectory makefile.
ifndef CLING_LEVEL
IS_TOP_LEVEL := 1
CLING_LEVEL := .
DIRS := include lib tools docs
PARALLEL_DIRS :=
ifeq ($(BUILD_EXAMPLES),1)
PARALLEL_DIRS += examples
endif
endif
ifeq ($(MAKECMDGOALS),libs-only)
DIRS := $(filter-out tools docs, $(DIRS))
OPTIONAL_DIRS :=
endif
###
# Common Makefile code, shared by all Cling Makefiles.
# Set LLVM source root level.
LEVEL := $(CLING_LEVEL)/../..
# Include LLVM common makefile.
include $(LEVEL)/Makefile.common
ifneq ($(ENABLE_DOCS),1)
DIRS := $(filter-out docs, $(DIRS))
endif
# Set common Cling build flags.
CPP.Flags += -I$(PROJ_SRC_DIR)/$(CLING_LEVEL)/include -I$(PROJ_OBJ_DIR)/$(CLING_LEVEL)/include
ifdef CLING_VENDOR
CPP.Flags += -DCLING_VENDOR='"$(CLING_VENDOR) "'
endif
# Disable -fstrict-aliasing. Darwin disables it by default (and LLVM doesn't
# work with it enabled with GCC), Cling/llvm-gc don't support it yet, and newer
# GCC's have false positive warnings with it on Linux (which prove a pain to
# fix). For example:
# http://gcc.gnu.org/PR41874
# http://gcc.gnu.org/PR41838
#
# We can revisit this when LLVM/Cling support it.
CXX.Flags += -fno-strict-aliasing
# Determine cling's version:
CLING_VERSION=$(shell cat "VERSION")
CPP.Flags += -DCLING_VERSION='"$(CLING_VERSION) "'
###
# Cling Top Level specific stuff.
ifeq ($(IS_TOP_LEVEL),1)
ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
$(RecursiveTargets)::
$(Verb) if [ ! -f test/Makefile ]; then \
$(MKDIR) test; \
$(CP) $(PROJ_SRC_DIR)/test/Makefile test/Makefile; \
fi
endif
test::
@ $(MAKE) -C test
report::
@ $(MAKE) -C test report
clean::
@ $(MAKE) -C test clean
libs-only: all
tags::
$(Verb) etags `find . -type f -name '*.h' -or -name '*.cpp' | \
grep -v /lib/Headers | grep -v /test/`
cscope.files:
find tools lib include -name '*.cpp' \
-or -name '*.def' \
-or -name '*.td' \
-or -name '*.h' > cscope.files
.PHONY: test report clean cscope.files
endif

View File

@ -0,0 +1,17 @@
//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// author: Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------
#ifndef CLING_VALUEPRINTERC_H
#define CLING_VALUEPRINTERC_H
#ifdef __cplusplus
extern "C"
#endif
void cling_PrintValue(void* /*cling::Value**/ V);
#endif // CLING_VALUEPRINTERC_H

View File

@ -0,0 +1,46 @@
#ifndef CLING_CTAGS_CALLBACK_H
#define CLING_CTAGS_CALLBACK_H
#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/InterpreterCallbacks.h"
#include "cling/TagsExtension/TagManager.h"
#include "clang/Sema/Lookup.h"
#if 0
This feature is disabled by default until stable.
To enable, execute the following code as runtime input.
Note that, for now, the T meta command will cause the interpreter to segfault,
unless these objects are loaded.
.rawInput 0
#include "cling/TagsExtension/TagManager.h"
#include "cling/TagsExtension/Callback.h"
cling::TagManager t;
gCling->setCallbacks(new cling::AutoloadCallback(gCling,&t));
#endif
namespace cling {
class LookupInfo{};
//TODO: Would contain info regarding previous lookups;
//TODO: get rid of the map in LookupObject
class AutoloadCallback : public cling::InterpreterCallbacks {
public:
AutoloadCallback(cling::Interpreter* interp, cling::TagManager* t);
using cling::InterpreterCallbacks::LookupObject;
//^to get rid of bogus warning : "-Woverloaded-virtual"
//virtual functions ARE meant to be overriden!
bool LookupObject (clang::LookupResult &R, clang::Scope *);
cling::TagManager* getTagManager();
private:
cling::Interpreter* m_Interpreter;
cling::TagManager* m_Tags;
};
}// end namespace cling
#endif

View File

@ -0,0 +1,36 @@
#include "Wrapper.h"
#include "readtags.h"
namespace cling {
///\brief Implements tag operations for Ctags
class CtagsFileWrapper:public TagFileWrapper {
public:
CtagsFileWrapper(std::string path, bool recurse=true,bool fileP=false);
~CtagsFileWrapper(){}
std::map<std::string,LookupResult> match
(std::string name, bool partialMatch=false);
bool newFile(){return m_Generated;}
bool validFile(){return m_Validfile;}
private:
void generate(const std::vector<std::string>& cmd,
std::string tagfile="adhoc");
void generate(std::string file);
void read();
struct TagFileInternals{
tagFile* tf;
tagFileInfo tfi;
};
TagFileInternals m_Tagfile;
std::string m_Tagfilename;
std::string m_Tagpath;
bool m_Generated;
bool m_Validfile;
};
}//end namespace cling

View File

@ -0,0 +1,40 @@
#ifndef CLING_TAG_MANAGER_H
#define CLING_TAG_MANAGER_H
#include <vector>
#include <map>
#include "cling/Interpreter/Interpreter.h"
#include "cling/TagsExtension/Wrapper.h"
namespace cling {
///\brief Class for managing all the available tag files
class TagManager {
public:
TagManager();
///\brief Information from a tag file lookup
class LookupInfo{
public:
LookupInfo(std::string h,std::string n,std::string t);
std::string header;
std::string name;
std::string type;
};
///\brief Add a new path from which a single tag file is generated
/// If recurse is true, path is recursively scanned but not preprocessed
/// else only the files directly in path are preprocessed and tagged
void AddTagFile(std::string path, bool recurse=true);
std::size_t size() { return m_Tags.size(); }
typedef std::multimap<std::string,LookupInfo> TableType;
TableType::iterator begin(std::string name);
TableType::iterator end(std::string name);
~TagManager();
private:
std::vector<TagFileWrapper*> m_Tags;
TableType m_Table;
};
}//end namespace cling
#endif

View File

@ -0,0 +1,42 @@
#ifndef CLING_CTAGS_WRAPPER_H
#define CLING_CTAGS_WRAPPER_H
// #include "readtags.h"
#include <vector>
#include <cstdlib>
#include <map>
#include <string>
namespace cling {
///\brief Different tag generating systems must inherit from TagFileWrapper
/// An object of a derived class represents a single tag file,
/// which may be generated from multiple header/source files
class TagFileWrapper {
public:
TagFileWrapper(std::string Path):m_Path(Path){}
struct LookupResult{
std::string name;
std::string kind;
};
///\brief Returns a map which associates a name with header files
/// and type of the name
/// When partialMatch is true, name can be a prefix of the values returned
virtual std::map<std::string,LookupResult>
match(std::string name, bool partialMatch=false)=0;
///\brief True if the file was generated and not already present
virtual bool newFile()=0;
///\brief True if the file is in a valid state
virtual bool validFile()=0;
virtual ~TagFileWrapper(){}
bool operator==(const TagFileWrapper& t) {return m_Path==t.m_Path;}
private:
std::string m_Path;
};
} //end namespace cling
#endif

View File

@ -8,6 +8,7 @@
add_subdirectory(Interpreter) add_subdirectory(Interpreter)
add_subdirectory(MetaProcessor) add_subdirectory(MetaProcessor)
add_subdirectory(TagsExtension)
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/UserInterface/textinput) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/UserInterface/textinput)
add_subdirectory(UserInterface) add_subdirectory(UserInterface)
endif() endif()

View File

@ -0,0 +1,379 @@
//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author: Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------
#include "cling/Interpreter/DynamicLibraryManager.h"
#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/InterpreterCallbacks.h"
#include "cling/Interpreter/InvocationOptions.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#ifdef WIN32
#include <Windows.h>
#include <shlobj.h>
#else
#include <limits.h> /* PATH_MAX */
#include <dlfcn.h>
#endif
namespace {
#if defined(LLVM_ON_UNIX)
static void GetSystemLibraryPaths(llvm::SmallVectorImpl<std::string>& Paths) {
char* env_var = getenv("LD_LIBRARY_PATH");
#if __APPLE__
if (!env_var)
env_var = getenv("DYLD_LIBRARY_PATH");
if (!env_var)
env_var = getenv("DYLD_FALLBACK_LIBRARY_PATH");
#endif
if (env_var != 0) {
static const char PathSeparator = ':';
const char* at = env_var;
const char* delim = strchr(at, PathSeparator);
while (delim != 0) {
std::string tmp(at, size_t(delim-at));
if (llvm::sys::fs::is_directory(tmp.c_str()))
Paths.push_back(tmp);
at = delim + 1;
delim = strchr(at, PathSeparator);
}
if (*at != 0)
if (llvm::sys::fs::is_directory(llvm::StringRef(at)))
Paths.push_back(at);
}
#if defined(__APPLE__) || defined(__CYGWIN__)
Paths.push_back("/usr/local/lib/");
Paths.push_back("/usr/X11R6/lib/");
Paths.push_back("/usr/lib/");
Paths.push_back("/lib/");
Paths.push_back("/lib/x86_64-linux-gnu/");
Paths.push_back("/usr/local/lib64/");
Paths.push_back("/usr/lib64/");
Paths.push_back("/lib64/");
#else
static bool initialized = false;
static std::vector<std::string> SysPaths;
if (!initialized) {
// trick to get the system search path
std::string cmd("LD_DEBUG=libs LD_PRELOAD=DOESNOTEXIST ls 2>&1");
FILE *pf = popen(cmd.c_str (), "r");
std::string result = "";
std::string sys_path = "";
char buffer[128];
while (!feof(pf)) {
if (fgets(buffer, 128, pf) != NULL)
result += buffer;
}
pclose(pf);
std::size_t from
= result.find("search path=", result.find("(LD_LIBRARY_PATH)"));
std::size_t to = result.find("(system search path)");
if (from != std::string::npos && to != std::string::npos) {
from += 12;
sys_path = result.substr(from, to-from);
sys_path.erase(std::remove_if(sys_path.begin(), sys_path.end(), isspace),
sys_path.end());
sys_path += ':';
}
static const char PathSeparator = ':';
const char* at = sys_path.c_str();
const char* delim = strchr(at, PathSeparator);
while (delim != 0) {
std::string tmp(at, size_t(delim-at));
if (llvm::sys::fs::is_directory(tmp.c_str()))
SysPaths.push_back(tmp);
at = delim + 1;
delim = strchr(at, PathSeparator);
}
initialized = true;
}
for (std::vector<std::string>::const_iterator I = SysPaths.begin(),
E = SysPaths.end(); I != E; ++I)
Paths.push_back((*I).c_str());
#endif
}
#elif defined(LLVM_ON_WIN32)
static void GetSystemLibraryPaths(llvm::SmallVectorImpl<std::string>& Paths) {
char buff[MAX_PATH];
// Generic form of C:\Windows\System32
HRESULT res = SHGetFolderPathA(NULL,
CSIDL_FLAG_CREATE | CSIDL_SYSTEM,
NULL,
SHGFP_TYPE_CURRENT,
buff);
if (res != S_OK) {
assert(0 && "Failed to get system directory");
return;
}
Paths.push_back(buff);
// Reset buff.
buff[0] = 0;
// Generic form of C:\Windows
res = SHGetFolderPathA(NULL,
CSIDL_FLAG_CREATE | CSIDL_WINDOWS,
NULL,
SHGFP_TYPE_CURRENT,
buff);
if (res != S_OK) {
assert(0 && "Failed to get windows directory");
return;
}
Paths.push_back(buff);
}
#else
# error "Unsupported platform."
#endif
}
namespace cling {
DynamicLibraryManager::DynamicLibraryManager(const InvocationOptions& Opts,
Interpreter& I)
: m_Opts(Opts), m_Interpreter(I) {
GetSystemLibraryPaths(m_SystemSearchPaths);
m_SystemSearchPaths.push_back(".");
}
DynamicLibraryManager::~DynamicLibraryManager() {}
static bool isSharedLib(llvm::StringRef LibName, bool* exists = 0) {
using namespace llvm::sys::fs;
file_magic Magic;
llvm::error_code Error = identify_magic(LibName, Magic);
bool onDisk = (Error == llvm::errc::success);
if (exists)
*exists = onDisk;
return onDisk &&
#ifdef __APPLE__
(Magic == file_magic::macho_fixed_virtual_memory_shared_lib
|| Magic == file_magic::macho_dynamically_linked_shared_lib
|| Magic == file_magic::macho_dynamically_linked_shared_lib_stub)
#elif defined(LLVM_ON_UNIX)
#ifdef __CYGWIN__
(Magic == file_magic::pecoff_executable)
#else
(Magic == file_magic::elf_shared_object)
#endif
#elif defined(LLVM_ON_WIN32)
(Magic == file_magic::pecoff_executable)
#else
# error "Unsupported platform."
#endif
;
}
std::string
DynamicLibraryManager::lookupLibInPaths(llvm::StringRef libStem) const {
llvm::SmallVector<std::string, 128>
Paths(m_Opts.LibSearchPath.begin(), m_Opts.LibSearchPath.end());
Paths.append(m_SystemSearchPaths.begin(), m_SystemSearchPaths.end());
for (llvm::SmallVectorImpl<std::string>::const_iterator
IPath = Paths.begin(), E = Paths.end();IPath != E; ++IPath) {
llvm::SmallString<512> ThisPath(*IPath); // FIXME: move alloc outside loop
llvm::sys::path::append(ThisPath, libStem);
bool exists;
if (isSharedLib(ThisPath.str(), &exists))
return ThisPath.str();
if (exists)
return "";
}
return "";
}
std::string
DynamicLibraryManager::lookupLibMaybeAddExt(llvm::StringRef libStem) const {
using namespace llvm::sys;
std::string foundDyLib = lookupLibInPaths(libStem);
if (foundDyLib.empty()) {
// Add DyLib extension:
llvm::SmallString<512> filenameWithExt(libStem);
#if defined(LLVM_ON_UNIX)
#ifdef __APPLE__
llvm::SmallString<512>::iterator IStemEnd = filenameWithExt.end() - 1;
#endif
static const char* DyLibExt = ".so";
#elif defined(LLVM_ON_WIN32)
static const char* DyLibExt = ".dll";
#else
# error "Unsupported platform."
#endif
filenameWithExt += DyLibExt;
foundDyLib = lookupLibInPaths(filenameWithExt);
#ifdef __APPLE__
if (foundDyLib.empty()) {
filenameWithExt.erase(IStemEnd + 1, filenameWithExt.end());
filenameWithExt += ".dylib";
FfgoundDyLib = lookupLibInPaths(filenameWithExt);
}
#endif
}
if (foundDyLib.empty())
return "";
// get canonical path name and check if already loaded
#if defined(LLVM_ON_WIN32)
llvm::SmallString<_MAX_PATH> FullPath("");
char *res = _fullpath((char *)FullPath.data(), foundDyLib.c_str(), _MAX_PATH);
#else
llvm::SmallString<PATH_MAX+1> FullPath("");
char *res = realpath(foundDyLib.c_str(), (char *)FullPath.data());
#endif
if (res == 0) {
llvm::errs() << "cling::DyLibMan::lookupLibMaybeAddExt(): error getting "
"real (canonical) path of library " << foundDyLib << '\n';
return foundDyLib;
}
FullPath.set_size(strlen(res));
return FullPath.str();
}
static std::string normalizePath(llvm::StringRef path) {
// Make the path canonical if the file exists.
struct stat buffer;
if (stat(path.data(), &buffer) != 0)
return "";
#if defined(LLVM_ON_WIN32)
char buf[_MAX_PATH];
char *res = _fullpath(buf, path.data(), _MAX_PATH);
#else
char buf[PATH_MAX+1];
char *res = realpath(path.data(), buf);
#endif
if (res == 0) {
assert(0 && "Cannot normalize!?");
return "";
}
return res;
}
std::string
DynamicLibraryManager::lookupLibrary(llvm::StringRef libStem) const {
llvm::SmallString<128> Absolute(libStem);
llvm::sys::fs::make_absolute(Absolute);
bool isAbsolute = libStem == Absolute;
// If it is an absolute path, don't try iterate over the paths.
if (isAbsolute) {
if (isSharedLib(libStem))
return normalizePath(libStem);
else
return "";
}
std::string foundName = lookupLibMaybeAddExt(libStem);
if (foundName.empty() && !libStem.startswith("lib")) {
// try with "lib" prefix:
foundName = lookupLibMaybeAddExt("lib" + libStem.str());
}
if (isSharedLib(foundName))
return normalizePath(foundName);
return "";
}
DynamicLibraryManager::LoadLibResult
DynamicLibraryManager::loadLibrary(const std::string& libStem,
bool permanent) {
std::string canonicalLoadedLib = lookupLibrary(libStem);
if (canonicalLoadedLib.empty())
return kLoadLibNotFound;
if (m_LoadedLibraries.find(canonicalLoadedLib) != m_LoadedLibraries.end())
return kLoadLibAlreadyLoaded;
std::string errMsg;
// TODO: !permanent case
#if defined(LLVM_ON_WIN32)
HMODULE dyLibHandle = LoadLibraryEx(canonicalLoadedLib.c_str(), NULL,
DONT_RESOLVE_DLL_REFERENCES);
errMsg = "LoadLibraryEx: GetLastError() returned ";
errMsg += GetLastError();
#else
const void* dyLibHandle = dlopen(canonicalLoadedLib.c_str(),
RTLD_LAZY|RTLD_GLOBAL);
if (const char* DyLibError = dlerror()) {
errMsg = DyLibError;
}
#endif
if (!dyLibHandle) {
llvm::errs() << "cling::DyLibMan::loadLibrary(): " << errMsg << '\n';
return kLoadLibLoadError;
}
else if (InterpreterCallbacks* C = m_Interpreter.getCallbacks())
C->LibraryLoaded(dyLibHandle, canonicalLoadedLib);
std::pair<DyLibs::iterator, bool> insRes
= m_DyLibs.insert(std::pair<DyLibHandle, std::string>(dyLibHandle,
canonicalLoadedLib));
if (!insRes.second)
return kLoadLibAlreadyLoaded;
m_LoadedLibraries.insert(canonicalLoadedLib);
return kLoadLibSuccess;
}
void DynamicLibraryManager::unloadLibrary(llvm::StringRef libStem) {
std::string canonicalLoadedLib = lookupLibrary(libStem);
if (!isLibraryLoaded(canonicalLoadedLib))
return;
DyLibHandle dyLibHandle = 0;
for (DyLibs::const_iterator I = m_DyLibs.begin(), E = m_DyLibs.end();
I != E; ++I) {
if (I->second == canonicalLoadedLib)
dyLibHandle = I->first;
}
std::string errMsg;
// TODO: !permanent case
#if defined(LLVM_ON_WIN32)
UnloadLibraryEx(dyLibHandle);
errMsg = "UnoadLibraryEx: GetLastError() returned ";
errMsg += GetLastError();
#else
dlclose(const_cast<void*>(dyLibHandle));
if (const char* DyLibError = dlerror()) {
errMsg = DyLibError;
}
#endif
if (InterpreterCallbacks* C = m_Interpreter.getCallbacks())
C->LibraryUnloaded(dyLibHandle, canonicalLoadedLib);
m_DyLibs.erase(dyLibHandle);
m_LoadedLibraries.erase(canonicalLoadedLib);
}
bool DynamicLibraryManager::isLibraryLoaded(llvm::StringRef fullPath) const {
std::string canonPath = normalizePath(fullPath);
if (m_LoadedLibraries.find(canonPath) != m_LoadedLibraries.end())
return true;
return false;
}
void DynamicLibraryManager::ExposeHiddenSharedLibrarySymbols(void* handle) {
llvm::sys::DynamicLibrary::addPermanentLibrary(const_cast<void*>(handle));
}
} // end namespace cling

View File

@ -9,7 +9,7 @@
##===----------------------------------------------------------------------===## ##===----------------------------------------------------------------------===##
LEVEL = ../../.. LEVEL = ../../..
PARALLEL_DIRS = Interpreter MetaProcessor UserInterface Utils PARALLEL_DIRS = Interpreter TagsExtension MetaProcessor UserInterface Utils
include $(LEVEL)/Makefile.common include $(LEVEL)/Makefile.common

View File

@ -116,7 +116,7 @@ namespace cling {
if (resultValue) if (resultValue)
*resultValue = Value(); *resultValue = Value();
return isLCommand(actionResult) return isLCommand(actionResult)
|| isXCommand(actionResult, resultValue) || isXCommand(actionResult, resultValue) ||isTCommand(actionResult)
|| isAtCommand() || isAtCommand()
|| isqCommand() || isUCommand(actionResult) || isICommand() || isqCommand() || isUCommand(actionResult) || isICommand()
|| isOCommand() || israwInputCommand() || isprintDebugCommand() || isOCommand() || israwInputCommand() || isprintDebugCommand()
@ -148,6 +148,27 @@ namespace cling {
// TODO: Some fine grained diagnostics // TODO: Some fine grained diagnostics
return result; return result;
} }
// T := 'T' FilePath Comment
// FilePath := AnyString
// AnyString := .*^('\t' Comment)
bool MetaParser::isTCommand(MetaSema::ActionResult& actionResult) {
bool result = false;
if (getCurTok().is(tok::ident) && getCurTok().getIdent().equals("T")) {
consumeAnyStringToken(tok::comment);
if (getCurTok().is(tok::raw_ident)) {
result = true;
actionResult = m_Actions->actOnTCommand(getCurTok().getIdent());
consumeToken();
if (getCurTok().is(tok::comment)) {
consumeAnyStringToken(tok::eof);
m_Actions->actOnComment(getCurTok().getIdent());
}
}
}
// TODO: Some fine grained diagnostics
return result;
}
// >RedirectCommand := '>' FilePath // >RedirectCommand := '>' FilePath
// FilePath := AnyString // FilePath := AnyString

View File

@ -33,6 +33,7 @@ namespace cling {
// ClassCommand | GCommand | StoreStateCommand | // ClassCommand | GCommand | StoreStateCommand |
// CompareStateCommand | StatsCommand | undoCommand // CompareStateCommand | StatsCommand | undoCommand
// LCommand := 'L' FilePath // LCommand := 'L' FilePath
// TCommand := 'T' FilePath
// >Command := '>' FilePath // >Command := '>' FilePath
// qCommand := 'q' // qCommand := 'q'
// XCommand := 'x' FilePath[ArgList] | 'X' FilePath[ArgList] // XCommand := 'x' FilePath[ArgList] | 'X' FilePath[ArgList]
@ -80,6 +81,7 @@ namespace cling {
bool isCommand(MetaSema::ActionResult& actionResult, bool isCommand(MetaSema::ActionResult& actionResult,
Value* resultValue); Value* resultValue);
bool isLCommand(MetaSema::ActionResult& actionResult); bool isLCommand(MetaSema::ActionResult& actionResult);
bool isTCommand(MetaSema::ActionResult& actionResult);
bool isRedirectCommand(MetaSema::ActionResult& actionResult); bool isRedirectCommand(MetaSema::ActionResult& actionResult);
bool isExtraArgList(); bool isExtraArgList();
bool isXCommand(MetaSema::ActionResult& actionResult, bool isXCommand(MetaSema::ActionResult& actionResult,

View File

@ -16,6 +16,7 @@
#include "cling/Interpreter/Transaction.h" #include "cling/Interpreter/Transaction.h"
#include "cling/Interpreter/Value.h" #include "cling/Interpreter/Value.h"
#include "cling/MetaProcessor/MetaProcessor.h" #include "cling/MetaProcessor/MetaProcessor.h"
#include "cling/TagsExtension/Callback.h"
#include "../lib/Interpreter/IncrementalParser.h" #include "../lib/Interpreter/IncrementalParser.h"
@ -28,6 +29,7 @@
#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringRef.h"
#include "llvm/ExecutionEngine/GenericValue.h" #include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/Support/Casting.h"
#include "clang/Lex/Preprocessor.h" #include "clang/Lex/Preprocessor.h"
@ -70,6 +72,22 @@ namespace cling {
return AR_Failure; return AR_Failure;
} }
MetaSema::ActionResult MetaSema::actOnTCommand(llvm::StringRef file) {
//llvm::outs()<<file<<": directory to be recursively tagged.\n";
AutoloadCallback *ctic= static_cast<AutoloadCallback*> (m_Interpreter.getCallbacks());
//FIXME: Temporary Implementation
// May cause a segfault if .T is used when the CTags callback is not set
// This will require modifying Interpreter to 'know' about the extension
if (ctic){
auto path=m_Interpreter.lookupFileOrLibrary(file);
if(path != "")
file = path;
ctic->getTagManager()->AddTagFile(file);
return AR_Success;
}
else return AR_Failure;
}
MetaSema::ActionResult MetaSema::actOnRedirectCommand(llvm::StringRef file, MetaSema::ActionResult MetaSema::actOnRedirectCommand(llvm::StringRef file,
MetaProcessor::RedirectionScope stream, MetaProcessor::RedirectionScope stream,
bool append) { bool append) {

View File

@ -65,6 +65,14 @@ namespace cling {
/// ///
ActionResult actOnLCommand(llvm::StringRef file); ActionResult actOnLCommand(llvm::StringRef file);
///\brief T command prepares the tag files for giving semantic hints.
///
///\param[in] file - The directory to be loaded.
///
ActionResult actOnTCommand(llvm::StringRef file);
///\brief < Redirect command. ///\brief < Redirect command.
/// ///
///\param[in] file - The file where the output is redirected ///\param[in] file - The file where the output is redirected

View File

@ -0,0 +1,18 @@
#------------------------------------------------------------------------------
# CLING - the C++ LLVM-based InterpreterG :)
#
# This file is dual-licensed: you can choose to license it under the University
# of Illinois Open Source License or the GNU Lesser General Public License. See
# LICENSE.TXT for details.
#------------------------------------------------------------------------------
add_cling_library(clingCtagsExtension
CtagsWrapper.cpp
Callback.cpp
readtags.cpp
TagManager.cpp
FSUtils.cpp
LINK_LIBS
clangBasic
)

View File

@ -0,0 +1,52 @@
#include "cling/TagsExtension/Callback.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/SmallVector.h"
#include "clang/Sema/Sema.h"
#include "llvm/Support/Path.h"
namespace cling {
bool AutoloadCallback::LookupObject (clang::LookupResult &R, clang::Scope *){
std::string in=R.getLookupName().getAsString();
clang::Sema& sema= m_Interpreter->getSema();
unsigned id = sema.getDiagnostics().getCustomDiagID
(clang::DiagnosticsEngine::Level::Warning,
"Note: '%0' can be found in %1");
unsigned idn = sema.getDiagnostics().getCustomDiagID
(clang::DiagnosticsEngine::Level::Note,
"Type : %0 , Full Path: %1");
for (auto it = m_Tags->begin(in); it != m_Tags->end(in); ++it)
{
auto lookup = it->second;
clang::SourceLocation loc = R.getNameLoc();
if (loc.isInvalid())
continue;
sema.Diags.Report(R.getNameLoc(),id)
<< lookup.name
<< llvm::sys::path::filename(lookup.header);
sema.Diags.Report(R.getNameLoc(),idn)
<< lookup.type
<< lookup.header;
}
return false;
}
AutoloadCallback::AutoloadCallback
(cling::Interpreter* interp, TagManager *t) :
InterpreterCallbacks(interp,true),
m_Interpreter(interp),
m_Tags(t) {
//TODO : Invoke stdandard c++ tagging here
}
TagManager* AutoloadCallback::getTagManager() {
return m_Tags;
}
}//end namespace cling

View File

@ -0,0 +1,124 @@
#include "cling/TagsExtension/CtagsWrapper.h"
#include "llvm/ADT/StringRef.h"
#include "FSUtils.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/FileSystem.h"
namespace cling {
CtagsFileWrapper::CtagsFileWrapper(std::string path, bool recurse, bool fileP)
:TagFileWrapper(path) {
// llvm::errs()<<path<<'\n';
// m_Tagfile = new TagFileInternals();
if (fileP) {
generate(path);
read();
return;
}
if (recurse) {
std::vector<std::string> list;
llvm::error_code ec;
llvm::sys::fs::recursive_directory_iterator rdit(path,ec);
while (rdit != decltype(rdit)()) {
auto entry = *rdit;
if (llvm::sys::fs::is_regular_file (entry.path())
&& isHeaderFile(entry.path())) {
//llvm::outs()<<entry.path()<<"\n";
list.push_back(entry.path());
}
rdit.increment(ec);
}
generate(list,path);
read();
}
else {
llvm::error_code ec;
llvm::sys::fs::directory_iterator dit(path, ec);
std::vector<std::string> list;
while (dit != decltype(dit)()){// !=end iterator
auto entry = *dit;
if (llvm::sys::fs::is_regular_file (entry.path()))
//llvm::outs()<<entry.path()<<"\n";
list.push_back(entry.path());
dit.increment(ec);
}
///auto pair=splitPath(path);
///TODO Preprocess the files in list and generate tags for them
}
}
std::map<std::string,TagFileWrapper::LookupResult>
CtagsFileWrapper::match(std::string name, bool partialMatch){
std::map<std::string,LookupResult> map;
tagEntry entry;
int options = TAG_OBSERVECASE | (partialMatch?TAG_PARTIALMATCH:TAG_FULLMATCH);
tagResult result = tagsFind(m_Tagfile.tf, &entry, name.c_str(), options);
while (result==TagSuccess){
LookupResult r;
r.name = entry.name;
r.kind = entry.kind;
map[entry.file] = r;
result=tagsFindNext(m_Tagfile.tf, &entry);
}
return map;
}
void CtagsFileWrapper::generate(std::string file) {
m_Tagpath = generateTagPath();
m_Tagfilename = pathToFileName(file);
if (!needToGenerate(m_Tagpath,m_Tagfilename, file)){
m_Generated=false;
return;
}
std::string cmd = "ctags --language-force=c++ -f "+m_Tagpath+m_Tagfilename+" "+file;
// llvm::errs()<<cmd<<"\n";
system(cmd.c_str());
}
//no more than `arglimit` arguments in a single invocation
void CtagsFileWrapper::generate
(const std::vector<std::string>& paths, std::string dirpath){
std::string concat;
m_Tagpath = generateTagPath();
m_Tagfilename = pathToFileName(dirpath);
if (!needToGenerate(m_Tagpath,m_Tagfilename, dirpath)){
m_Generated = false;
return;
}
auto it=paths.begin(),end=paths.end();
while (it != end){
concat+=(*it+" ");
it++;
}
//TODO: Convert these to twine
std::string filename = " -f "+m_Tagpath+m_Tagfilename+" ";
std::string lang = " --language-force=c++ ";
std::string sorted = " --sort=yes ";
std::string append = " -a ";
std::string cmd = "ctags "+append+lang+filename+sorted+concat;
// llvm::errs()<<cmd<<"\n";
std::system(cmd.c_str());
m_Generated = true;
}
void CtagsFileWrapper::read() {
m_Tagfile.tf = tagsOpen
((m_Tagpath+m_Tagfilename).c_str(), &(m_Tagfile.tfi));
//std::cout<<"File "<<tagpath+tagfilename<<" read.\n";
if (m_Tagfile.tfi.status.opened == false)
m_Validfile = false;
else
m_Validfile = true;
}
}

View File

@ -0,0 +1,69 @@
#include "FSUtils.h"
#include <string>
#include <cstdlib>
#include <algorithm>
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
namespace cling {
std::pair<std::string,std::string> splitPath(std::string path){
auto filename=llvm::sys::path::filename(path);
llvm::SmallString<128> p(path.begin(),path.end());
llvm::sys::path::remove_filename(p);
return {p.c_str(),filename};
}
std::string pathToFileName(std::string path){
for(auto& c:path)
if(c == '/')
c = '_';
return path;
}
bool fileIsNewer(std::string path,std::string dir){
return true;//TODO Timestamp checks go here
}
bool needToGenerate(std::string tagpath,
std::string filename, std::string dirpath){
if( llvm::sys::fs::exists(tagpath+filename)) {
return false;
}
else if (!fileIsNewer(tagpath+filename,dirpath)){
return false;
}
else {
//std::cout<<"File doesn't exist";
return true;
}
}
//FIXME: Replace when this is available in llvm::sys::path
std::string get_separator() {
#ifdef LLVM_ON_WIN32
const char preferred_separator = '\\';
#else
const char preferred_separator = '/';
#endif
return {preferred_separator};
}
std::string generateTagPath(){
llvm::SmallString<30> home_ss;
llvm::sys::path::home_directory(home_ss);
std::string homedir=home_ss.c_str();
if (homedir == "")
homedir = ".";
std::string tagdir=get_separator() +".cling/";
std::string result=homedir+tagdir;
llvm::sys::fs::create_directory(result);
return result;
}
bool isHeaderFile(llvm::StringRef str){
return str.endswith(".h")
||str.endswith(".hpp")
||str.find("include")!=llvm::StringRef::npos;
}
}//end namespace cling

View File

@ -0,0 +1,19 @@
#ifndef CLING_FS_UTILS_H
#define CLING_FS_UTILS_H
#include "llvm/ADT/StringRef.h"
namespace cling {
std::string pathToFileName(std::string path);
bool fileIsNewer(std::string path, std::string dir);
bool needToGenerate(std::string tagpath,
std::string filename, std::string dirpath);
std::string generateTagPath();
bool isHeaderFile(llvm::StringRef str);
std::pair<std::string,std::string> splitPath(std::string path);
} //end namespace cling
#endif

View File

@ -0,0 +1,23 @@
##===- cling/lib/TagsExtension/Makefile---------------------*- Makefile -*-===##
#
# The Cling Interpreter
#
# This file is dual-licensed: you can choose to license it under the University
# of Illinois Open Source License or the GNU Lesser General Public License. See
# LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
#
# This implements the a C++ interpreter user frontend.
#
##===----------------------------------------------------------------------===##
CLING_LEVEL = ../..
LIBRARYNAME := clingTagsExtension
BUILD_ARCHIVE = 1
CXXFLAGS = -fno-rtti
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_SRC_DIR)/../../../clang/include \
-I$(PROJ_SRC_DIR)/../../../clang/lib -I$(PROJ_OBJ_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../../clang/include
include $(CLING_LEVEL)/Makefile

View File

@ -0,0 +1,70 @@
#include "cling/TagsExtension/TagManager.h"
#include "cling/TagsExtension/CtagsWrapper.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/FileSystem.h"
#include <algorithm>
namespace cling {
TagManager::TagManager(){}
void TagManager::AddTagFile(std::string path, bool recurse){
bool fileP = false;
if (llvm::sys::fs::is_regular_file(path)) {
fileP = true;
}
if (llvm::sys::path::is_relative(path)) {
llvm::SmallString<100> str(path.data());
llvm::error_code ec = llvm::sys::fs::make_absolute(str);
if (ec != llvm::errc::success)
llvm::errs()<<"Can't deduce absolute path.\n";
else
path = str.c_str();
}
TagFileWrapper* tf = new CtagsFileWrapper(path,recurse,fileP);
if (!tf->validFile()) {
llvm::errs() << "Reading Tag File: " << path << " failed.\n";
return;
}
bool eq = false;
for (auto& t:m_Tags) {
if (*t == *tf ) {
eq=true;
break;
}
}
if (!eq) {
m_Tags.push_back(tf);
}
}
TagManager::TableType::iterator
TagManager::begin(std::string name){
m_Table.erase(name);
for (auto& t:m_Tags){
for (auto match:t->match(name, true)){
LookupInfo l(match.first, match.second.name, match.second.kind);
m_Table.insert({name, l});
}
}
auto r = m_Table.equal_range(name);
return r.first;
}
TagManager::TableType::iterator
TagManager::end(std::string name){
auto r = m_Table.equal_range(name);
return r.second;
}
TagManager::LookupInfo::LookupInfo
(std::string h, std::string n, std::string t):
header(h), name(n), type(t){}
TagManager::~TagManager() {
for (auto& tag : m_Tags )
delete tag;
}
} //end namespace cling

View File

@ -0,0 +1,959 @@
/*
* $Id: readtags.c 592 2007-07-31 03:30:41Z dhiebert $
*
* Copyright (c) 1996-2003, Darren Hiebert
*
* This source code is released into the public domain.
*
* This module contains functions for reading tag files.
*/
/*
* INCLUDE FILES
*/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h> /* to declare off_t */
#include "readtags.h"
/*
* MACROS
*/
#define TAB '\t'
/*
* DATA DECLARATIONS
*/
typedef struct {
size_t size;
char *buffer;
} vstring;
/* Information about current tag file */
struct sTagFile {
/* has the file been opened and this structure initialized? */
short initialized;
/* format of tag file */
short format;
/* how is the tag file sorted? */
sortType sortMethod;
/* pointer to file structure */
FILE* fp;
/* file position of first character of `line' */
off_t pos;
/* size of tag file in seekable positions */
off_t size;
/* last line read */
vstring line;
/* name of tag in last line read */
vstring name;
/* defines tag search state */
struct {
/* file position of last match for tag */
off_t pos;
/* name of tag last searched for */
char *name;
/* length of name for partial matches */
size_t nameLength;
/* peforming partial match */
short partial;
/* ignoring case */
short ignorecase;
} search;
/* miscellaneous extension fields */
struct {
/* number of entries in `list' */
unsigned short max;
/* list of key value pairs */
tagExtensionField *list;
} fields;
/* buffers to be freed at close */
struct {
/* name of program author */
char *author;
/* name of program */
char *name;
/* URL of distribution */
char *url;
/* program version */
char *version;
} program;
};
/*
* DATA DEFINITIONS
*/
const char *const EmptyString = "";
const char *const PseudoTagPrefix = "!_";
/*
* FUNCTION DEFINITIONS
*/
/*
* Compare two strings, ignoring case.
* Return 0 for match, < 0 for smaller, > 0 for bigger
* Make sure case is folded to uppercase in comparison (like for 'sort -f')
* This makes a difference when one of the chars lies between upper and lower
* ie. one of the chars [ \ ] ^ _ ` for ascii. (The '_' in particular !)
*/
static int struppercmp (const char *s1, const char *s2)
{
int result;
do
{
result = toupper ((int) *s1) - toupper ((int) *s2);
} while (result == 0 && *s1++ != '\0' && *s2++ != '\0');
return result;
}
static int strnuppercmp (const char *s1, const char *s2, size_t n)
{
int result;
do
{
result = toupper ((int) *s1) - toupper ((int) *s2);
} while (result == 0 && --n > 0 && *s1++ != '\0' && *s2++ != '\0');
return result;
}
static int growString (vstring *s)
{
int result = 0;
size_t newLength;
char *newLine;
if (s->size == 0)
{
newLength = 128;
newLine = (char*) malloc (newLength);
*newLine = '\0';
}
else
{
newLength = 2 * s->size;
newLine = (char*) realloc (s->buffer, newLength);
}
if (newLine == NULL)
perror ("string too large");
else
{
s->buffer = newLine;
s->size = newLength;
result = 1;
}
return result;
}
/* Copy name of tag out of tag line */
static void copyName (tagFile *const file)
{
size_t length;
const char *end = strchr (file->line.buffer, '\t');
if (end == NULL)
{
end = strchr (file->line.buffer, '\n');
if (end == NULL)
end = strchr (file->line.buffer, '\r');
}
if (end != NULL)
length = end - file->line.buffer;
else
length = strlen (file->line.buffer);
while (length >= file->name.size)
growString (&file->name);
strncpy (file->name.buffer, file->line.buffer, length);
file->name.buffer [length] = '\0';
}
static int readTagLineRaw (tagFile *const file)
{
int result = 1;
int reReadLine;
/* If reading the line places any character other than a null or a
* newline at the last character position in the buffer (one less than
* the buffer size), then we must resize the buffer and reattempt to read
* the line.
*/
do
{
char *const pLastChar = file->line.buffer + file->line.size - 2;
char *line;
file->pos = ftell (file->fp);
reReadLine = 0;
*pLastChar = '\0';
line = fgets (file->line.buffer, (int) file->line.size, file->fp);
if (line == NULL)
{
/* read error */
if (! feof (file->fp))
perror ("readTagLine");
result = 0;
}
else if (*pLastChar != '\0' &&
*pLastChar != '\n' && *pLastChar != '\r')
{
/* buffer overflow */
growString (&file->line);
fseek (file->fp, file->pos, SEEK_SET);
reReadLine = 1;
}
else
{
size_t i = strlen (file->line.buffer);
while (i > 0 &&
(file->line.buffer [i - 1] == '\n' || file->line.buffer [i - 1] == '\r'))
{
file->line.buffer [i - 1] = '\0';
--i;
}
}
} while (reReadLine && result);
if (result)
copyName (file);
return result;
}
static int readTagLine (tagFile *const file)
{
int result;
do
{
result = readTagLineRaw (file);
} while (result && *file->name.buffer == '\0');
return result;
}
static tagResult growFields (tagFile *const file)
{
tagResult result = TagFailure;
unsigned short newCount = (unsigned short) 2 * file->fields.max;
tagExtensionField *newFields = (tagExtensionField*)
realloc (file->fields.list, newCount * sizeof (tagExtensionField));
if (newFields == NULL)
perror ("too many extension fields");
else
{
file->fields.list = newFields;
file->fields.max = newCount;
result = TagSuccess;
}
return result;
}
static void parseExtensionFields (tagFile *const file, tagEntry *const entry,
char *const string)
{
char *p = string;
while (p != NULL && *p != '\0')
{
while (*p == TAB)
*p++ = '\0';
if (*p != '\0')
{
char *colon;
char *field = p;
p = strchr (p, TAB);
if (p != NULL)
*p++ = '\0';
colon = strchr (field, ':');
if (colon == NULL)
entry->kind = field;
else
{
const char *key = field;
const char *value = colon + 1;
*colon = '\0';
if (strcmp (key, "kind") == 0)
entry->kind = value;
else if (strcmp (key, "file") == 0)
entry->fileScope = 1;
else if (strcmp (key, "line") == 0)
entry->address.lineNumber = atol (value);
else
{
if (entry->fields.count == file->fields.max)
growFields (file);
file->fields.list [entry->fields.count].key = key;
file->fields.list [entry->fields.count].value = value;
++entry->fields.count;
}
}
}
}
}
static void parseTagLine (tagFile *file, tagEntry *const entry)
{
int i;
char *p = file->line.buffer;
char *tab = strchr (p, TAB);
entry->fields.list = NULL;
entry->fields.count = 0;
entry->kind = NULL;
entry->fileScope = 0;
entry->name = p;
if (tab != NULL)
{
*tab = '\0';
p = tab + 1;
entry->file = p;
tab = strchr (p, TAB);
if (tab != NULL)
{
int fieldsPresent;
*tab = '\0';
p = tab + 1;
if (*p == '/' || *p == '?')
{
/* parse pattern */
int delimiter = *(unsigned char*) p;
entry->address.lineNumber = 0;
entry->address.pattern = p;
do
{
p = strchr (p + 1, delimiter);
} while (p != NULL && *(p - 1) == '\\');
if (p == NULL)
{
/* invalid pattern */
}
else
++p;
}
else if (isdigit ((int) *(unsigned char*) p))
{
/* parse line number */
entry->address.pattern = p;
entry->address.lineNumber = atol (p);
while (isdigit ((int) *(unsigned char*) p))
++p;
}
else
{
/* invalid pattern */
}
fieldsPresent = (strncmp (p, ";\"", 2) == 0);
*p = '\0';
if (fieldsPresent)
parseExtensionFields (file, entry, p + 2);
}
}
if (entry->fields.count > 0)
entry->fields.list = file->fields.list;
for (i = entry->fields.count ; i < file->fields.max ; ++i)
{
file->fields.list [i].key = NULL;
file->fields.list [i].value = NULL;
}
}
static char *duplicate (const char *str)
{
char *result = NULL;
if (str != NULL)
{
result = strdup (str);
if (result == NULL)
perror (NULL);
}
return result;
}
static void readPseudoTags (tagFile *const file, tagFileInfo *const info)
{
fpos_t startOfLine;
const size_t prefixLength = strlen (PseudoTagPrefix);
if (info != NULL)
{
info->file.format = 1;
info->file.sort = TAG_UNSORTED;
info->program.author = NULL;
info->program.name = NULL;
info->program.url = NULL;
info->program.version = NULL;
}
while (1)
{
fgetpos (file->fp, &startOfLine);
if (! readTagLine (file))
break;
if (strncmp (file->line.buffer, PseudoTagPrefix, prefixLength) != 0)
break;
else
{
tagEntry entry;
const char *key, *value;
parseTagLine (file, &entry);
key = entry.name + prefixLength;
value = entry.file;
if (strcmp (key, "TAG_FILE_SORTED") == 0)
file->sortMethod = (sortType) atoi (value);
else if (strcmp (key, "TAG_FILE_FORMAT") == 0)
file->format = (short) atoi (value);
else if (strcmp (key, "TAG_PROGRAM_AUTHOR") == 0)
file->program.author = duplicate (value);
else if (strcmp (key, "TAG_PROGRAM_NAME") == 0)
file->program.name = duplicate (value);
else if (strcmp (key, "TAG_PROGRAM_URL") == 0)
file->program.url = duplicate (value);
else if (strcmp (key, "TAG_PROGRAM_VERSION") == 0)
file->program.version = duplicate (value);
if (info != NULL)
{
info->file.format = file->format;
info->file.sort = file->sortMethod;
info->program.author = file->program.author;
info->program.name = file->program.name;
info->program.url = file->program.url;
info->program.version = file->program.version;
}
}
}
fsetpos (file->fp, &startOfLine);
}
static void gotoFirstLogicalTag (tagFile *const file)
{
fpos_t startOfLine;
const size_t prefixLength = strlen (PseudoTagPrefix);
rewind (file->fp);
while (1)
{
fgetpos (file->fp, &startOfLine);
if (! readTagLine (file))
break;
if (strncmp (file->line.buffer, PseudoTagPrefix, prefixLength) != 0)
break;
}
fsetpos (file->fp, &startOfLine);
}
static tagFile *initialize (const char *const filePath, tagFileInfo *const info)
{
tagFile *result = (tagFile*) calloc ((size_t) 1, sizeof (tagFile));
if (result != NULL)
{
growString (&result->line);
growString (&result->name);
result->fields.max = 20;
result->fields.list = (tagExtensionField*) calloc (
result->fields.max, sizeof (tagExtensionField));
result->fp = fopen (filePath, "r");
if (result->fp == NULL)
{
free (result);
result = NULL;
info->status.error_number = errno;
}
else
{
fseek (result->fp, 0, SEEK_END);
result->size = ftell (result->fp);
rewind (result->fp);
readPseudoTags (result, info);
info->status.opened = 1;
result->initialized = 1;
}
}
return result;
}
static void terminate (tagFile *const file)
{
fclose (file->fp);
free (file->line.buffer);
free (file->name.buffer);
free (file->fields.list);
if (file->program.author != NULL)
free (file->program.author);
if (file->program.name != NULL)
free (file->program.name);
if (file->program.url != NULL)
free (file->program.url);
if (file->program.version != NULL)
free (file->program.version);
if (file->search.name != NULL)
free (file->search.name);
memset (file, 0, sizeof (tagFile));
free (file);
}
static tagResult readNext (tagFile *const file, tagEntry *const entry)
{
tagResult result;
if (file == NULL || ! file->initialized)
result = TagFailure;
else if (! readTagLine (file))
result = TagFailure;
else
{
if (entry != NULL)
parseTagLine (file, entry);
result = TagSuccess;
}
return result;
}
static const char *readFieldValue (
const tagEntry *const entry, const char *const key)
{
const char *result = NULL;
int i;
if (strcmp (key, "kind") == 0)
result = entry->kind;
else if (strcmp (key, "file") == 0)
result = EmptyString;
else for (i = 0 ; i < entry->fields.count && result == NULL ; ++i)
if (strcmp (entry->fields.list [i].key, key) == 0)
result = entry->fields.list [i].value;
return result;
}
static int readTagLineSeek (tagFile *const file, const off_t pos)
{
int result = 0;
if (fseek (file->fp, pos, SEEK_SET) == 0)
{
result = readTagLine (file); /* read probable partial line */
if (pos > 0 && result)
result = readTagLine (file); /* read complete line */
}
return result;
}
static int nameComparison (tagFile *const file)
{
int result;
if (file->search.ignorecase)
{
if (file->search.partial)
result = strnuppercmp (file->search.name, file->name.buffer,
file->search.nameLength);
else
result = struppercmp (file->search.name, file->name.buffer);
}
else
{
if (file->search.partial)
result = strncmp (file->search.name, file->name.buffer,
file->search.nameLength);
else
result = strcmp (file->search.name, file->name.buffer);
}
return result;
}
static void findFirstNonMatchBefore (tagFile *const file)
{
#define JUMP_BACK 512
int more_lines;
int comp;
off_t start = file->pos;
off_t pos = start;
do
{
if (pos < (off_t) JUMP_BACK)
pos = 0;
else
pos = pos - JUMP_BACK;
more_lines = readTagLineSeek (file, pos);
comp = nameComparison (file);
} while (more_lines && comp == 0 && pos > 0 && pos < start);
}
static tagResult findFirstMatchBefore (tagFile *const file)
{
tagResult result = TagFailure;
int more_lines;
off_t start = file->pos;
findFirstNonMatchBefore (file);
do
{
more_lines = readTagLine (file);
if (nameComparison (file) == 0)
result = TagSuccess;
} while (more_lines && result != TagSuccess && file->pos < start);
return result;
}
static tagResult findBinary (tagFile *const file)
{
tagResult result = TagFailure;
off_t lower_limit = 0;
off_t upper_limit = file->size;
off_t last_pos = 0;
off_t pos = upper_limit / 2;
while (result != TagSuccess)
{
if (! readTagLineSeek (file, pos))
{
/* in case we fell off end of file */
result = findFirstMatchBefore (file);
break;
}
else if (pos == last_pos)
{
/* prevent infinite loop if we backed up to beginning of file */
break;
}
else
{
const int comp = nameComparison (file);
last_pos = pos;
if (comp < 0)
{
upper_limit = pos;
pos = lower_limit + ((upper_limit - lower_limit) / 2);
}
else if (comp > 0)
{
lower_limit = pos;
pos = lower_limit + ((upper_limit - lower_limit) / 2);
}
else if (pos == 0)
result = TagSuccess;
else
result = findFirstMatchBefore (file);
}
}
return result;
}
static tagResult findSequential (tagFile *const file)
{
tagResult result = TagFailure;
if (file->initialized)
{
while (result == TagFailure && readTagLine (file))
{
if (nameComparison (file) == 0)
result = TagSuccess;
}
}
return result;
}
static tagResult find (tagFile *const file, tagEntry *const entry,
const char *const name, const int options)
{
tagResult result;
if (file->search.name != NULL)
free (file->search.name);
file->search.name = duplicate (name);
file->search.nameLength = strlen (name);
file->search.partial = (options & TAG_PARTIALMATCH) != 0;
file->search.ignorecase = (options & TAG_IGNORECASE) != 0;
fseek (file->fp, 0, SEEK_END);
file->size = ftell (file->fp);
rewind (file->fp);
if ((file->sortMethod == TAG_SORTED && !file->search.ignorecase) ||
(file->sortMethod == TAG_FOLDSORTED && file->search.ignorecase))
{
#ifdef DEBUG
printf ("<performing binary search>\n");
#endif
result = findBinary (file);
}
else
{
#ifdef DEBUG
printf ("<performing sequential search>\n");
#endif
result = findSequential (file);
}
if (result != TagSuccess)
file->search.pos = file->size;
else
{
file->search.pos = file->pos;
if (entry != NULL)
parseTagLine (file, entry);
}
return result;
}
static tagResult findNext (tagFile *const file, tagEntry *const entry)
{
tagResult result;
if ((file->sortMethod == TAG_SORTED && !file->search.ignorecase) ||
(file->sortMethod == TAG_FOLDSORTED && file->search.ignorecase))
{
result = tagsNext (file, entry);
if (result == TagSuccess && nameComparison (file) != 0)
result = TagFailure;
}
else
{
result = findSequential (file);
if (result == TagSuccess && entry != NULL)
parseTagLine (file, entry);
}
return result;
}
/*
* EXTERNAL INTERFACE
*/
extern tagFile *tagsOpen (const char *const filePath, tagFileInfo *const info)
{
return initialize (filePath, info);
}
extern tagResult tagsSetSortType (tagFile *const file, const sortType type)
{
tagResult result = TagFailure;
if (file != NULL && file->initialized)
{
file->sortMethod = type;
result = TagSuccess;
}
return result;
}
extern tagResult tagsFirst (tagFile *const file, tagEntry *const entry)
{
tagResult result = TagFailure;
if (file != NULL && file->initialized)
{
gotoFirstLogicalTag (file);
result = readNext (file, entry);
}
return result;
}
extern tagResult tagsNext (tagFile *const file, tagEntry *const entry)
{
tagResult result = TagFailure;
if (file != NULL && file->initialized)
result = readNext (file, entry);
return result;
}
extern const char *tagsField (const tagEntry *const entry, const char *const key)
{
const char *result = NULL;
if (entry != NULL)
result = readFieldValue (entry, key);
return result;
}
extern tagResult tagsFind (tagFile *const file, tagEntry *const entry,
const char *const name, const int options)
{
tagResult result = TagFailure;
if (file != NULL && file->initialized)
result = find (file, entry, name, options);
return result;
}
extern tagResult tagsFindNext (tagFile *const file, tagEntry *const entry)
{
tagResult result = TagFailure;
if (file != NULL && file->initialized)
result = findNext (file, entry);
return result;
}
extern tagResult tagsClose (tagFile *const file)
{
tagResult result = TagFailure;
if (file != NULL && file->initialized)
{
terminate (file);
result = TagSuccess;
}
return result;
}
/*
* TEST FRAMEWORK
*/
#ifdef READTAGS_MAIN
static const char *TagFileName = "tags";
static const char *ProgramName;
static int extensionFields;
static int SortOverride;
static sortType SortMethod;
static void printTag (const tagEntry *entry)
{
int i;
int first = 1;
const char* separator = ";\"";
const char* const empty = "";
/* "sep" returns a value only the first time it is evaluated */
#define sep (first ? (first = 0, separator) : empty)
printf ("%s\t%s\t%s",
entry->name, entry->file, entry->address.pattern);
if (extensionFields)
{
if (entry->kind != NULL && entry->kind [0] != '\0')
printf ("%s\tkind:%s", sep, entry->kind);
if (entry->fileScope)
printf ("%s\tfile:", sep);
#if 0
if (entry->address.lineNumber > 0)
printf ("%s\tline:%lu", sep, entry->address.lineNumber);
#endif
for (i = 0 ; i < entry->fields.count ; ++i)
printf ("%s\t%s:%s", sep, entry->fields.list [i].key,
entry->fields.list [i].value);
}
putchar ('\n');
#undef sep
}
static void findTag (const char *const name, const int options)
{
tagFileInfo info;
tagEntry entry;
tagFile *const file = tagsOpen (TagFileName, &info);
if (file == NULL)
{
fprintf (stderr, "%s: cannot open tag file: %s: %s\n",
ProgramName, strerror (info.status.error_number), name);
exit (1);
}
else
{
if (SortOverride)
tagsSetSortType (file, SortMethod);
if (tagsFind (file, &entry, name, options) == TagSuccess)
{
do
{
printTag (&entry);
} while (tagsFindNext (file, &entry) == TagSuccess);
}
tagsClose (file);
}
}
static void listTags (void)
{
tagFileInfo info;
tagEntry entry;
tagFile *const file = tagsOpen (TagFileName, &info);
if (file == NULL)
{
fprintf (stderr, "%s: cannot open tag file: %s: %s\n",
ProgramName, strerror (info.status.error_number), TagFileName);
exit (1);
}
else
{
while (tagsNext (file, &entry) == TagSuccess)
printTag (&entry);
tagsClose (file);
}
}
const char *const Usage =
"Find tag file entries matching specified names.\n\n"
"Usage: %s [-ilp] [-s[0|1]] [-t file] [name(s)]\n\n"
"Options:\n"
" -e Include extension fields in output.\n"
" -i Perform case-insensitive matching.\n"
" -l List all tags.\n"
" -p Perform partial matching.\n"
" -s[0|1|2] Override sort detection of tag file.\n"
" -t file Use specified tag file (default: \"tags\").\n"
"Note that options are acted upon as encountered, so order is significant.\n";
extern int main (int argc, char **argv)
{
int options = 0;
int actionSupplied = 0;
int i;
ProgramName = argv [0];
if (argc == 1)
{
fprintf (stderr, Usage, ProgramName);
exit (1);
}
for (i = 1 ; i < argc ; ++i)
{
const char *const arg = argv [i];
if (arg [0] != '-')
{
findTag (arg, options);
actionSupplied = 1;
}
else
{
size_t j;
for (j = 1 ; arg [j] != '\0' ; ++j)
{
switch (arg [j])
{
case 'e': extensionFields = 1; break;
case 'i': options |= TAG_IGNORECASE; break;
case 'p': options |= TAG_PARTIALMATCH; break;
case 'l': listTags (); actionSupplied = 1; break;
case 't':
if (arg [j+1] != '\0')
{
TagFileName = arg + j + 1;
j += strlen (TagFileName);
}
else if (i + 1 < argc)
TagFileName = argv [++i];
else
{
fprintf (stderr, Usage, ProgramName);
exit (1);
}
break;
case 's':
SortOverride = 1;
++j;
if (arg [j] == '\0')
SortMethod = TAG_SORTED;
else if (strchr ("012", arg[j]) != NULL)
SortMethod = (sortType) (arg[j] - '0');
else
{
fprintf (stderr, Usage, ProgramName);
exit (1);
}
break;
default:
fprintf (stderr, "%s: unknown option: %c\n",
ProgramName, arg[j]);
exit (1);
break;
}
}
}
}
if (! actionSupplied)
{
fprintf (stderr,
"%s: no action specified: specify tag name(s) or -l option\n",
ProgramName);
exit (1);
}
return 0;
}
#endif
/* vi:set tabstop=4 shiftwidth=4: */

View File

@ -0,0 +1,252 @@
/*
* $Id: readtags.h 443 2006-05-30 04:37:13Z darren $
*
* Copyright (c) 1996-2003, Darren Hiebert
*
* This source code is released for the public domain.
*
* This file defines the public interface for looking up tag entries in tag
* files.
*
* The functions defined in this interface are intended to provide tag file
* support to a software tool. The tag lookups provided are sufficiently fast
* enough to permit opening a sorted tag file, searching for a matching tag,
* then closing the tag file each time a tag is looked up (search times are
* on the order of hundreths of a second, even for huge tag files). This is
* the recommended use of this library for most tool applications. Adhering
* to this approach permits a user to regenerate a tag file at will without
* the tool needing to detect and resynchronize with changes to the tag file.
* Even for an unsorted 24MB tag file, tag searches take about one second.
*/
#ifndef READTAGS_H
#define READTAGS_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* MACROS
*/
/* Options for tagsSetSortType() */
typedef enum {
TAG_UNSORTED, TAG_SORTED, TAG_FOLDSORTED
} sortType ;
/* Options for tagsFind() */
#define TAG_FULLMATCH 0x0
#define TAG_PARTIALMATCH 0x1
#define TAG_OBSERVECASE 0x0
#define TAG_IGNORECASE 0x2
/*
* DATA DECLARATIONS
*/
typedef enum { TagFailure = 0, TagSuccess = 1 } tagResult;
struct sTagFile;
typedef struct sTagFile tagFile;
/* This structure contains information about the tag file. */
typedef struct {
struct {
/* was the tag file successfully opened? */
int opened;
/* errno value when 'opened' is false */
int error_number;
} status;
/* information about the structure of the tag file */
struct {
/* format of tag file (1 = original, 2 = extended) */
short format;
/* how is the tag file sorted? */
sortType sort;
} file;
/* information about the program which created this tag file */
struct {
/* name of author of generating program (may be null) */
const char *author;
/* name of program (may be null) */
const char *name;
/* URL of distribution (may be null) */
const char *url;
/* program version (may be null) */
const char *version;
} program;
} tagFileInfo;
/* This structure contains information about an extension field for a tag.
* These exist at the end of the tag in the form "key:value").
*/
typedef struct {
/* the key of the extension field */
const char *key;
/* the value of the extension field (may be an empty string) */
const char *value;
} tagExtensionField;
/* This structure contains information about a specific tag. */
typedef struct {
/* name of tag */
const char *name;
/* path of source file containing definition of tag */
const char *file;
/* address for locating tag in source file */
struct {
/* pattern for locating source line
* (may be NULL if not present) */
const char *pattern;
/* line number in source file of tag definition
* (may be zero if not known) */
unsigned long lineNumber;
} address;
/* kind of tag (may by name, character, or NULL if not known) */
const char *kind;
/* is tag of file-limited scope? */
short fileScope;
/* miscellaneous extension fields */
struct {
/* number of entries in `list' */
unsigned short count;
/* list of key value pairs */
tagExtensionField *list;
} fields;
} tagEntry;
/*
* FUNCTION PROTOTYPES
*/
/*
* This function must be called before calling other functions in this
* library. It is passed the path to the tag file to read and a (possibly
* null) pointer to a structure which, if not null, will be populated with
* information about the tag file. If successful, the function will return a
* handle which must be supplied to other calls to read information from the
* tag file, and info.status.opened will be set to true. If unsuccessful,
* info.status.opened will be set to false and info.status.error_number will
* be set to the errno value representing the system error preventing the tag
* file from being successfully opened.
*/
extern tagFile *tagsOpen (const char *const filePath, tagFileInfo *const info);
/*
* This function allows the client to override the normal automatic detection
* of how a tag file is sorted. Permissible values for `type' are
* TAG_UNSORTED, TAG_SORTED, TAG_FOLDSORTED. Tag files in the new extended
* format contain a key indicating whether or not they are sorted. However,
* tag files in the original format do not contain such a key even when
* sorted, preventing this library from taking advantage of fast binary
* lookups. If the client knows that such an unmarked tag file is indeed
* sorted (or not), it can override the automatic detection. Note that
* incorrect lookup results will result if a tag file is marked as sorted when
* it actually is not. The function will return TagSuccess if called on an
* open tag file or TagFailure if not.
*/
extern tagResult tagsSetSortType (tagFile *const file, const sortType type);
/*
* Reads the first tag in the file, if any. It is passed the handle to an
* opened tag file and a (possibly null) pointer to a structure which, if not
* null, will be populated with information about the first tag file entry.
* The function will return TagSuccess another tag entry is found, or
* TagFailure if not (i.e. it reached end of file).
*/
extern tagResult tagsFirst (tagFile *const file, tagEntry *const entry);
/*
* Step to the next tag in the file, if any. It is passed the handle to an
* opened tag file and a (possibly null) pointer to a structure which, if not
* null, will be populated with information about the next tag file entry. The
* function will return TagSuccess another tag entry is found, or TagFailure
* if not (i.e. it reached end of file). It will always read the first tag in
* the file immediately after calling tagsOpen().
*/
extern tagResult tagsNext (tagFile *const file, tagEntry *const entry);
/*
* Retrieve the value associated with the extension field for a specified key.
* It is passed a pointer to a structure already populated with values by a
* previous call to tagsNext(), tagsFind(), or tagsFindNext(), and a string
* containing the key of the desired extension field. If no such field of the
* specified key exists, the function will return null.
*/
extern const char *tagsField (const tagEntry *const entry, const char *const key);
/*
* Find the first tag matching `name'. The structure pointed to by `entry'
* will be populated with information about the tag file entry. If a tag file
* is sorted using the C locale, a binary search algorithm is used to search
* the tag file, resulting in very fast tag lookups, even in huge tag files.
* Various options controlling the matches can be combined by bit-wise or-ing
* certain values together. The available values are:
*
* TAG_PARTIALMATCH
* Tags whose leading characters match `name' will qualify.
*
* TAG_FULLMATCH
* Only tags whose full lengths match `name' will qualify.
*
* TAG_IGNORECASE
* Matching will be performed in a case-insenstive manner. Note that
* this disables binary searches of the tag file.
*
* TAG_OBSERVECASE
* Matching will be performed in a case-senstive manner. Note that
* this enables binary searches of the tag file.
*
* The function will return TagSuccess if a tag matching the name is found, or
* TagFailure if not.
*/
extern tagResult tagsFind (tagFile *const file, tagEntry *const entry, const char *const name, const int options);
/*
* Find the next tag matching the name and options supplied to the most recent
* call to tagsFind() for the same tag file. The structure pointed to by
* `entry' will be populated with information about the tag file entry. The
* function will return TagSuccess if another tag matching the name is found,
* or TagFailure if not.
*/
extern tagResult tagsFindNext (tagFile *const file, tagEntry *const entry);
/*
* Call tagsTerminate() at completion of reading the tag file, which will
* close the file and free any internal memory allocated. The function will
* return TagFailure is no file is currently open, TagSuccess otherwise.
*/
extern tagResult tagsClose (tagFile *const file);
#ifdef __cplusplus
}
#endif
#endif
/* vi:set tabstop=4 shiftwidth=4: */

View File

@ -0,0 +1,210 @@
//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------
// RUN: cat %s | %cling -Xclang -verify | FileCheck %s
#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/Value.h"
cling::Value V;
V // CHECK: (cling::Value &) <<<invalid>>> @0x{{.*}}
gCling->evaluate("return 1;", V);
V // CHECK: (cling::Value &) boxes [(int) 1]
gCling->evaluate("(void)V", V);
V // CHECK-NEXT: (cling::Value &) boxes [(void) @0x{{.*}}]
// Returns must put the result in the Value.
bool cond = true;
gCling->evaluate("if (cond) return \"true\"; else return 0;", V);
V // CHECK-NEXT: (cling::Value &) boxes [(const char [5]) "true"]
gCling->evaluate("if (cond) return; else return 12;", V);
V // CHECK-NEXT: (cling::Value &) boxes [(void) @0x{{.*}}]
gCling->evaluate("if (cond) return; int aa = 12;", V);
V // CHECK-NEXT: (cling::Value &) boxes [(void) @0x{{.*}}]
gCling->evaluate("cond = false; if (cond) return \"true\"; else return 0;", V);
V // CHECK-NEXT: (cling::Value &) boxes [(int) 0]
gCling->evaluate("auto a = 12.3; a;", V);
V // CHECK: (cling::Value &) boxes [(double) 1.230000e+01]
long LongV = 17;
gCling->evaluate("LongV;", V);
V // CHECK: (cling::Value &) boxes [(long) 17]
int* IntP = (int*)0x12;
gCling->evaluate("IntP;", V);
V // CHECK: (cling::Value &) boxes [(int *) 0x12]
cling::Value Result;
gCling->evaluate("V", Result);
// Here we check what happens for record type like cling::Value; they are returned by reference.
Result // CHECK: (cling::Value &) boxes [(cling::Value &) boxes [(int *) 0x12]]
V // CHECK: (cling::Value &) boxes [(int *) 0x12]
// Savannah #96277
gCling->evaluate("gCling->declare(\"double sin(double);\"); double one = sin(3.141/2);", V);
V // CHECK: (cling::Value &) boxes [(double) 1.000000e+00]
gCling->process("double one = sin(3.141/2);", &V);
V // CHECK: (cling::Value &) boxes [(double) 1.000000e+00]
one // CHECK: (double) 1.000
int one; // expected-error {{redefinition of 'one' with a different type: 'int' vs 'double'}} expected-note {{previous definition is here}}
// Make sure that PR#98434 doesn't get reintroduced.
.rawInput
void f(int) { return; }
.rawInput
gCling->evaluate("f", V);
V.isValid() //CHECK: {{\([_]B|b}}ool) true
// end PR#98434
// Check lifetime of objects in Value
.rawInput 1
struct WithDtor {
static int fgCount;
WithDtor() { ++fgCount; }
WithDtor(const WithDtor&) { ++fgCount; }
~WithDtor() { --fgCount; }
};
int WithDtor::fgCount = 0;
WithDtor getWithDtor() { return WithDtor(); }
#include <vector>
std::vector<WithDtor> getWithDtorVec() { std::vector<WithDtor> ret; ret.resize(7); return ret; }
.rawInput 0
cling::Value* VOnHeap = new cling::Value();
gCling->evaluate("getWithDtor()", *VOnHeap);
*VOnHeap //CHECK: (cling::Value &) boxes [(WithDtor) @0x{{.*}}]
WithDtor::fgCount //CHECK: (int) 1
delete VOnHeap;
WithDtor::fgCount //CHECK: (int) 0
// Check destructor call for templates
VOnHeap = new cling::Value();
gCling->evaluate("getWithDtorVec()", *VOnHeap);
*VOnHeap //CHECK: (cling::Value &) boxes [(std::vector<WithDtor>) @0x{{.*}}]
WithDtor::fgCount //CHECK: (int) 7
delete VOnHeap;
WithDtor::fgCount //CHECK: (int) 0
// long doubles (tricky for the JIT).
gCling->evaluate("17.42L", V);
V // CHECK: (cling::Value &) boxes [(long double) 17.42{{[0-9]*}}L]
// Test references, temporaries
.rawInput 1
extern "C" int printf(const char*,...);
struct Tracer {
std::string Content;
static int InstanceCount;
Tracer(const char* str): Content(str) { ++InstanceCount; dump("ctor"); }
Tracer(const Tracer& o): Content(o.Content + "+") {
++InstanceCount; dump("copy");
}
~Tracer() {--InstanceCount; dump("dtor");}
std::string asStr() const {
return Content + "{" + (char)('0' + InstanceCount) + "}";
}
void dump(const char* tag) { printf("%s:%s\n", asStr().c_str(), tag); }
};
int Tracer::InstanceCount = 0;
Tracer ObjMaker() { return Tracer("MADE"); }
Tracer& RefMaker() { static Tracer R("REF"); return R; }
const Tracer& ConstRefMaker() {static Tracer R("CONSTREF"); return R;}
namespace cling {
// FIXME: inline printValue is not used by PrintClingValue()!
std::string printValue(const Tracer* const p, const Tracer* const u,
const ValuePrinterInfo& VPI) {
return p->asStr();
}
}
void dumpTracerSVR(cling::Value& svr) {
((Tracer*)svr.getAs<void*>())->dump("dump");
}
.rawInput 0
// Creating the static in constructs one object. It gets returned by
// reference; it should only be destructed by ~JIT, definitely not by
// ~Value (which should only store a Tracer&)
gCling->evaluate("RefMaker()", V);
// This is the local static:
// CHECK: REF{1}:ctor
printf("RefMaker() done\n"); // CHECK-NEXT: RefMaker() done
V // CHECK-NEXT: (cling::Value &) boxes [(Tracer &) @{{.*}}]
dumpTracerSVR(V); // CHECK-NEXT: REF{1}:dump
// Setting a new value should destruct the old - BUT it's a ref thus no
// destruction.
// Create a temporary. Copies it into V through placement-new and copy
// construction. The latter is elided; the temporary *is* what's stored in V.
// Thus all we see is the construction of the temporary.
gCling->evaluate("ObjMaker()", V);
// The temporary gets created:
// CHECK-NEXT:MADE{2}:ctor
printf("ObjMaker() done\n"); //CHECK-NEXT: ObjMaker() done
V // CHECK-NEXT: (cling::Value &) boxes [(Tracer) @{{.*}}]
dumpTracerSVR(V); // CHECK-NEXT: MADE{2}:dump
// Creating a variable:
Tracer RT("VAR"); // CHECK-NEXT: VAR{3}:ctor
// The following is a declRefExpr of lvalue type. We explicitly treat this as
// a reference; i.e. the cling::Value will claim to store a Tracer&. No extra
// construction, no extra allocation should happen.
//
// Setting a new value should destruct the old:
// CHECK-NEXT: MADE{2}:dtor
gCling->evaluate("RT", V); // should not call any ctor!
printf("RT done\n"); //CHECK-NEXT: RT done
V // CHECK-NEXT: (cling::Value &) boxes [(Tracer &) @{{.*}}]
dumpTracerSVR(V); // CHECK-NEXT: VAR{2}:dump
// The following creates a copy, explicitly. This temporary object is then put
// into the Value.
//
gCling->evaluate("(Tracer)RT", V);
// Copies RT:
//CHECK-NEXT: VAR+{3}:copy
printf("(Tracer)RT done\n"); //CHECK-NEXT: RT done
V // CHECK-NEXT: (cling::Value &) boxes [(Tracer) @{{.*}}]
dumpTracerSVR(V); // CHECK-NEXT: VAR+{3}:dump
// Check eval of array var
Tracer arrV[] = {ObjMaker(), ObjMaker(), ObjMaker()};
// The array is built:
//CHECK-NEXT: MADE{4}:ctor
//CHECK-NEXT: MADE{5}:ctor
//CHECK-NEXT: MADE{6}:ctor
gCling->evaluate("arrV", V);
// Now V gets destructed...
//CHECK-NEXT: VAR+{5}:dtor
// ...and the elements are copied:
//CHECK-NEXT: MADE+{6}:copy
//CHECK-NEXT: MADE+{7}:copy
//CHECK-NEXT: MADE+{8}:copy
V // CHECK-NEXT: (cling::Value &) boxes [(Tracer [3]) { @{{.*}}, @{{.*}}, @{{.*}} }]
// Destruct the variables with static storage:
// Destruct arrV:
//CHECK-NEXT: MADE{7}:dtor
//CHECK-NEXT: MADE{6}:dtor
//CHECK-NEXT: MADE{5}:dtor
// CHECK-NEXT: VAR{4}:dtor
// CHECK-NEXT: REF{3}:dtor
//CHECK-NEXT: MADE+{2}:dtor
//CHECK-NEXT: MADE+{1}:dtor
//CHECK-NEXT: MADE+{0}:dtor

View File

@ -0,0 +1,29 @@
//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------
// RUN: cat %s | %cling 2>&1
#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/LookupHelper.h"
#include "clang/AST/Decl.h"
const cling::LookupHelper& lookup = gCling->getLookupHelper();
cling::LookupHelper::DiagSetting diags = cling::LookupHelper::WithDiagnostics;
template <typename T> struct S {
T var[3];
};
template <typename T> struct A {
static void* fun() { return (void*)typename T::x(); }
};
const clang::Decl* G = lookup.findScope("", diags);
.storeState "beforeLookup"
lookup.findClassTemplate("S<void>", diags)
lookup.findFunctionArgs(G, "A<int>::fun", "0", diags);
.compareState "beforeLookup"

View File

@ -0,0 +1,29 @@
/*------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//----------------------------------------------------------------------------*/
// same test as test_01.c but ensuring the .c file to be processed
// is in the working directory (issue ROOT-6244)
// RUN: cd `dirname %s` ; %cling %s | FileCheck %s
extern "C" int printf(const char*,...);
const char* defaultArgV[] = {"A default argument", "", 0};
int test_exec_in_same_dir(int argc=12, const char** argv = defaultArgV)
{
int i;
for( i = 0; i < 5; ++i )
printf( "Hello World #%d\n", i );
// CHECK: Hello World #0
// CHECK: Hello World #1
// CHECK: Hello World #2
// CHECK: Hello World #3
// CHECK: Hello World #4
return 0;
}

View File

@ -0,0 +1,25 @@
//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------
// RUN: cat %s | %cling -I %S -Xclang -verify
// Test LookupTest
#include "cling/TagsExtension/TagManager.h"
#include "cling/TagsExtension/Callback.h"
cling::TagManager t;
gCling->setCallbacks(new cling::AutoloadCallback(gCling,&t));
.T TestHeader.h
TestClass t;
//expected-warning + {{}}
//expected-note + {{}}
//expected-error {{}}
.q

View File

@ -0,0 +1,28 @@
//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------
// RUN: cat %s | %cling -I %S 2>&1 | FileCheck %s
// Test NoDups
#include "cling/TagsExtension/TagManager.h"
#include "cling/TagsExtension/Callback.h"
cling::TagManager t;
gCling->setCallbacks(new cling::AutoloadCallback(gCling,&t));
.T TestHeader.h
.T TestHeader.h
.T TestHeader.h
t.size()
//CHECK: (std::size_t) 1
.q

View File

@ -0,0 +1 @@
class TestClass{};

View File

@ -30,6 +30,7 @@ target_link_libraries(cling
clingMetaProcessor clingMetaProcessor
clingInterpreter clingInterpreter
clingUtils clingUtils
clingCtagsExtension
) )
install(TARGETS cling install(TARGETS cling

View File

@ -21,7 +21,7 @@ CXXFLAGS = -fno-rtti
NO_DEAD_STRIP := 1 NO_DEAD_STRIP := 1
LINK_COMPONENTS := bitwriter jit native option ipo instrumentation objcarcopts LINK_COMPONENTS := bitwriter jit native option ipo instrumentation objcarcopts
USEDLIBS = clingUserInterface.a clingMetaProcessor.a clingInterpreter.a clingUITextInput.a clingUtils.a clangFrontend.a clangSerialization.a clangDriver.a clangCodeGen.a clangParse.a clangSema.a clangEdit.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a USEDLIBS = clingUserInterface.a clingMetaProcessor.a clingTagsExtension.a clingInterpreter.a clingUITextInput.a clingUtils.a clangFrontend.a clangSerialization.a clangDriver.a clangCodeGen.a clangParse.a clangSema.a clangEdit.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a
include $(LEVEL)/Makefile.common include $(LEVEL)/Makefile.common