Skip to content

Commit

Permalink
[Backport 5.0] Highlighting: improve C++ (#49362)
Browse files Browse the repository at this point in the history
Several small improvements to the C++ highlighting queries to improve
readability.

- Treat destructors as functions, same as constructors
- Treat `unsigned` and `signed` as builtin types, same as primitive
types like `bool`
- Treat all-uppercase variables as identifiers instead of constants
- Treat function declarations with field names as functions instead of
fields
- Treat `operator` in `operator==` as a keyword
- Remove usages of `IdentifierOperator` because it's noisy,
doesn't improve readability of the code and there were many false
positives in the implementation
- Include `~` in destructor names
- Handle C++ attributes
- Handle C++ literal suffixes
- Adds new minimized test case for various language features

## Test plan

See updated snapshot tests.


<!-- All pull requests REQUIRE a test plan:
https://docs.sourcegraph.com/dev/background-information/testing_principles
-->
 <br> Backport 93a1101 from #49254

Co-authored-by: Ólafur Páll Geirsson <olafurpg@gmail.com>
  • Loading branch information
github-actions[bot] and olafurpg committed Mar 15, 2023
1 parent 7419d69 commit f3ee4b8
Show file tree
Hide file tree
Showing 6 changed files with 1,363 additions and 407 deletions.
Original file line number Diff line number Diff line change
@@ -1,24 +1,3 @@

"--" @operator
"-" @operator
"-=" @operator
"->" @operator
"=" @operator
"!=" @operator
"*" @operator
"&" @operator
"&&" @operator
"+" @operator
"++" @operator
"+=" @operator
"<" @operator
"==" @operator
">" @operator
"||" @operator

"." @delimiter
";" @delimiter

(string_literal) @string
(system_lib_string) @string

Expand All @@ -34,26 +13,31 @@
function: (field_expression
field: (field_identifier) @identifier.function))
(function_declarator
declarator: (identifier) @identifier.function)
declarator: [
(identifier)
(field_identifier)
] @identifier.function)

(destructor_name (identifier) @skip) @identifier.function
(preproc_function_def
name: (identifier) @identifier.function)

(attribute name: (identifier) @identifier.attribute)
(field_identifier) @identifier.attribute
(statement_identifier) @identifier.attribute
(type_identifier) @type
(static_assert_declaration ("static_assert") @identifier.builtin)
(primitive_type) @type.builtin
(sized_type_specifier) @type

((identifier) @constant
(#match? @constant "^[A-Z][A-Z\\d_]*$"))
(sized_type_specifier) @type.builtin

(literal_suffix) @identifier
(identifier) @identifier
(namespace_identifier) @identifier.module

(this) @constant.builtin
(comment) @comment
(operator_name) @identifier.operator
(operator_name "operator" @keyword)
(operator_name) @identifier
(auto) @keyword

[
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Stripped down from llvm/ADT/SmallSet.h (the code doesn't make sense)

//===----------------------------------------------------------------------===//
///
/// \file
/// This file defines the SmallSet class.
///
//===----------------------------------------------------------------------===//

#ifndef BAD_SMALLSET_H
#define BAD_SMALLSET_H

#include "llvm/ADT/SmallPtrSet.h"
#include <utility>

namespace llvm {

/// Doc comment
template <typename T, unsigned N, const char *P, typename C = std::less<T>>
class SmallSetIterator
: public iterator_facade_base<SmallSetIterator<T, N>,
std::forward_iterator_tag, T> {
private:
using SetIterTy = typename std::set<T, C>::const_iterator;
using VecIterTy = typename SmallVector<T, N>::const_iterator;
using SelfTy = SmallSetIterator<T, N, C>;

// Non-doc comment
union {
SetIterTy SetIter;
VecIterTy VecIter;
};

bool isSmall;

public:
SmallSetIterator(SetIterTy SetIter) : SetIter(SetIter), isSmall(false) {}

~SmallSetIterator() {
if (isSmall)
VecIter.~VecIterTy();
}

SmallSetIterator(SmallSetIterator &&Other) : isSmall(Other.isSmall) {
if (isSmall)
VecIter = std::move(Other.VecIter);
else
// In-code comment
new (&SetIter) SetIterTy(std::move(Other.SetIter));
}

SmallSetIterator& operator=(const SmallSetIterator& Other) {
return *this;
}

bool operator==(const SmallSetIterator &RHS) const {
if (isSmall != RHS.isSmall)
return false;
if (isSmall)
return VecIter == RHS.VecIter;
}

SmallSetIterator &operator++() {
SetIter++;
return *this;
}

const T &operator*() const { return isSmall ? *VecIter : *SetIter; }

static_assert(N <= 32); // C++17 extension
static_assert(N <= 32, "N should be small");
};

class SmallSet {
SmallVector<T, N> Vector;
std::set<T, C> Set;

public:
[[nodiscard]] bool empty() const { return Vector.empty(); }
[[nodiscard("PURE FUN")]] int strategic_value(int x, int y) { return x^y; }

std::pair<const_iterator, bool> insert(const T &V) {
if (!isSmall()) {
auto [I, Inserted] = Set.insert(V);
return std::make_pair(const_iterator(I), Inserted);
}
}

template <typename IterT>
void insert(IterT I, IterT E) {
for (; I != E; ++I)
insert(*I);
}

const_iterator begin() const {
if (isSmall())
return {Vector.begin()};
return {Set.begin()};
}
};

#endif // BAD_SMALLSET_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
#include <iostream>
#include <map>
#include <vector>

void rangeBasedLoops() {
std::vector<int> nums = {1, 2, 3, 4, 5};

// Iterate over vector using range-based for loop
for (int num : nums) {
std::cout << num << " ";
}
std::cout << std::endl;

std::map<std::string, int> ages = {{"Alice", 25}, {"Bob", 30}, {"Charlie", 35}};

// Iterate over map using range-based for loop
for (const auto& [name, age] : ages) {
std::cout << name << " is " << age << " years old." << std::endl;
}
}

void closures() {
int x = 5;

// Define closure with capture
auto add_x = [x](int y) {
return x + y;
};

// Call closure with different arguments
std::cout << add_x(10) << std::endl; // prints 15
}

// Define user-defined literal for string suffix "_s"
std::string operator"" _s(const char* str, std::size_t len) {
return std::string(str, len);
}

// Define user-defined literal for number suffix "_m"
constexpr int operator"" _m(unsigned long long x) {
return x * 1000;
}

void userDefinedLiterals() {
// Use custom string literal suffix "_s"
std::string s = "hello"_s;
std::cout << s << std::endl; // prints "hello"

int meters = 5_m;
std::cout << meters << " meters" << std::endl; // prints "5000 meters"
}

#pragma once

#include <iostream>

#pragma warning(push)
#pragma warning(disable: 4996)

int pragmas() {
#pragma message("This is a message from the preprocessor!")
std::cout << "Hello, world!" << std::endl;

return 0;
}

#pragma warning(pop)

#define MESSAGE "Hello, world! This is a very long message that spans multiple lines. " \
"It is being continued using the line continuation character."

#include <iostream>

void preprocessorContinuations() {
std::cout << MESSAGE << std::endl;
}


int andOrOperators() {
int x = 5;
int y = 10;
bool b1 = x > 3 and y < 20; // b1 is true
bool b2 = x < 3 or y > 20; // b2 is false
bool b3 = x > 3 and y > 20; // b3 is false
bool b4 = x < 3 or y < 20; // b4 is true
}


int multibyteCharacters() {
std::string s1 = "Hello, world!"; // single-byte characters
std::string s2 = "こんにちは世界!"; // multi-byte characters in UTF-8 encoding

char c1 = 'A'; // single-byte character
char c2 = u8''; // multi-byte character encoded in UTF-8


std::cout << s1 << std::endl;
std::cout << s2 << std::endl;

return 0;
}

void literals() {
auto intLit = 1234;
auto floatLit = 1.23f;
auto boolLit = true;
char charLit = 'x';
auto stringLit = "Hello";
auto wideStringLit = L"World";
auto rawStringLit = R"(Hello
World)";
auto nullptrLit = nullptr;
}


// Structs, enums, unions
struct Point {
int x;
int y;
Point() : x(0), y(0) { } // Default constructor
Point(int x, int y) : x(x), y(y) { } // Initialization constructor
};
enum Color {
Red,
Green,
Blue
};
union IntOrFloat {
int i;
float f;
};

void structsEnumsUnions() {
Point p {5, 10};
Color c = Blue;
IntOrFloat iof;
iof.i = 10; // Uses int member
iof.f = 3.14f; // Now uses float member
}

// Templates
template <typename T>
void swap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
template <typename T, unsigned N>
struct Array {
T data[N];
};

void templates() {
int x = 5, y = 10;
swap(x, y); // x is now 10, y is now 5
double d1 = 1.2, d2 = 3.4;
swap(d1, d2); // d1 is now 3.4, d2 is now 1.2
Array<int, 10> ints; // Holds 10 ints
Array<char, 100> chars; // Holds 100 chars
}

// Classes
class Person {
public:
Person(std::string name, int age); // Constructor
~Person(); // Destructor
std::string getName(); // Accessor method
// Virtual method
virtual void greeting();
// Overloaded operator
friend std::ostream& operator<<(std::ostream& os, const Person& p);
private:
std::string name;
int age;
};
class Employee : public Person { // Inherits from Person
public:
Employee(std::string name, int age, std::string company);
// Overridden virtual method
void greeting() override;
};

// Attributes
[[my_attribute]]
struct my_attribute {
int value;
};

namespace std {
template <>
struct has_attribute<my_attribute> : true_type { };
}

void attributes() {
[[my_attribute(5)]] int data;
if (has_attribute<my_attribute>(myData)) {
// data has the my_attribute attribute
}
}
}
Loading

0 comments on commit f3ee4b8

Please sign in to comment.