diff --git a/.overcommit.yml b/.overcommit.yml index 8990590ea..b5c787a34 100644 --- a/.overcommit.yml +++ b/.overcommit.yml @@ -20,11 +20,6 @@ PreCommit: RuboCop: enabled: true - Solargraph: - enabled: true - exclude: - - 'spec/**/*' - FixMe: enabled: true exclude: diff --git a/.rubocop.yml b/.rubocop.yml index 51b022f51..be7b0afbe 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -64,3 +64,4 @@ plugins: - rubocop-rspec - rubocop-rake - rubocop-yard + - solargraph diff --git a/Rakefile b/Rakefile index f27abfeb6..faa518e33 100755 --- a/Rakefile +++ b/Rakefile @@ -136,3 +136,21 @@ task :overcommit do # OVERCOMMIT_DEBUG=1 will show more detail sh 'SOLARGRAPH_ASSERTS=on bundle exec overcommit --run --diff origin/master' end + +desc 'Generate a new cop with a template' +task :new_cop, [:cop] do |_task, args| + require 'rubocop' + + cop_name = args.fetch(:cop) do + warn 'usage: bundle exec rake new_cop[Department/Name]' + exit! + end + + generator = RuboCop::Cop::Generator.new(cop_name) + + generator.write_source + generator.inject_require(root_file_path: 'lib/rubocop/cop/solargraph_cops.rb') + generator.inject_config(config_file_path: 'config/default.yml') + + puts generator.todo +end diff --git a/config/default.yml b/config/default.yml new file mode 100644 index 000000000..a0aa501bb --- /dev/null +++ b/config/default.yml @@ -0,0 +1,47 @@ +--- +Solargraph/Blah: + Description: 'Write a description of the cop.' + Enabled: true + VersionAdded: '<>' + +Solargraph/NewMeaninglessTag: + Description: 'Check meaningless tag' + Enabled: true + VersionAdded: '0.4.0' + +Solargraph/NewTagTypeSyntax: + Description: 'Check syntax for yard tag type' + Enabled: true + VersionAdded: '0.5.0' + +Solargraph/NewCollectionStyle: + Description: 'Check collection type style' + Enabled: true + VersionAdded: '0.5.0' + EnforcedStyle: long + SupportedStyles: + - long + - short + +Solargraph/NewCollectionType: + Description: 'Check collection type syntax' + Enabled: true + VersionAdded: '0.5.0' + EnforcedStyle: long + SupportedStyles: + - long + - short + +Solargraph/NewMismatchName: + Description: 'Check @param and @option name and method parameters' + Enabled: true + VersionAdded: '0.3.0' + EnforcedStylePrototypeName: after + SupportedStylesPrototypeName: + - before + - after + +Solargraph/NewTagTypePosition: + Description: 'Notice tag type position' + Enabled: true + VersionAdded: '0.9.0' diff --git a/lib/rubocop/cop/solargraph/type_violation.rb b/lib/rubocop/cop/solargraph/type_violation.rb new file mode 100644 index 000000000..9a06f0bf4 --- /dev/null +++ b/lib/rubocop/cop/solargraph/type_violation.rb @@ -0,0 +1,88 @@ +# frozen_string_literal: true + +require 'yard' +require 'rubocop-yard' +require 'solargraph' + +module ::RuboCop + module Cop + module Solargraph + # TODO: external_dependency_checksum should probably point to + # same things that invalidate Solargraph cache? Also solargraph + # config? + # TODO: Add one per type of typechecker error - there's a team concept' + class TypeViolation < ::RuboCop::Cop::Base + include RuboCop::Cop::YARD::Helper + include RangeHelp + + # @param config [RuboCop::Config, nil] + # @param options [Hash, nil] + def initialize(config = nil, options = nil) + @@directory = Dir.pwd + # directory = File.realpath(options[:directory]) TODO allow options + @@mutex ||= Mutex.new + @@workspace ||= ::Solargraph::Workspace.new(@@directory) + # level = options[:level].to_sym TODO + @@level = :strong + @@rules ||= @@workspace.rules(@@level) + @@mutex.synchronize do + # do this in a mutex as it takes a while and these get called in parallel + @@api_map ||= + ::Solargraph::ApiMap.load_with_cache(@@directory, $stdout, + loose_unions: + !@@rules.require_all_unique_types_support_call?) + end + super + end + + def self.support_multiple_source? + true + end + + # @return [void] + def on_new_investigation + file = processed_source.file_path + + + + checker = ::Solargraph::TypeChecker.new(file, + api_map: @@api_map, + rules: @@rules, level: @@level, + workspace: @@workspace) + # @return [::Array<::Solargraph::TypeChecker::Problem, nil>] + problems = nil + begin + problems = checker.problems + rescue ::Solargraph::FileNotFoundError + # not a file covered by solargraph config + return + end + + # @sg-ignore Declared type + # Array does not + # match inferred type nil for variable problems @type - I + # think because it doesn't understand the absolute + # ::Solargraph in the context of a class Solargraph + # + # @param problem [::Solargraph::TypeChecker::Problem] + problems.each do |problem| + # @type [::Parser::Source::Buffer] + buffer = processed_source.buffer + contents = buffer.source + location = problem.location + start_position = location.range.start + end_position = location.range.ending + begin_offset = ::Solargraph::Position.to_offset(contents, start_position) + end_offset = ::Solargraph::Position.to_offset(contents, end_position) + range = ::Parser::Source::Range.new(buffer, + begin_offset, + end_offset) + + + add_offense(range, message: problem.message) + end + end + end + end + end +end diff --git a/lib/rubocop/solargraph_cops.rb b/lib/rubocop/solargraph_cops.rb new file mode 100644 index 000000000..32fd467e7 --- /dev/null +++ b/lib/rubocop/solargraph_cops.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +require 'solargraph' + +require_relative 'cop/solargraph/type_violation' diff --git a/lib/solargraph.rb b/lib/solargraph.rb index 27a79e4ad..a573fc456 100755 --- a/lib/solargraph.rb +++ b/lib/solargraph.rb @@ -49,6 +49,7 @@ class InvalidRubocopVersionError < RuntimeError; end autoload :RbsMap, 'solargraph/rbs_map' autoload :GemPins, 'solargraph/gem_pins' autoload :PinCache, 'solargraph/pin_cache' + autoload :LintRoller, 'solargraph/lint_roller' dir = File.dirname(__FILE__) VIEWS_PATH = File.join(dir, 'solargraph', 'views') diff --git a/lib/solargraph/lint_roller.rb b/lib/solargraph/lint_roller.rb new file mode 100644 index 000000000..54eff7788 --- /dev/null +++ b/lib/solargraph/lint_roller.rb @@ -0,0 +1,53 @@ +require 'lint_roller' + +module Solargraph + module LintRoller + class Plugin < ::LintRoller::Plugin + # @param config [Hash{String => String}] options passed to the plugin by the user + def initialize(config) + config['require_path'] = 'solargraph/rubocop' + super + end + + # @sg-ignore Declared return type ::LintRoller::About does not + # match inferred type Solargraph::LintRoller::Plugin for + # Solargraph::LintRoller::Plugin#about + # @return [LintRoller::About] + def about + # @sg-ignore Unrecognized keyword argument name to Struct.new + ::LintRoller::About.new( + name: "solargraph", + version: Solargraph::VERSION, + homepage: "https://github.com/castwide/solargraph", + description: "Configuration of Solargraph typechecking" + ) + end + + # @sg-ignore Solargraph::LintRoller::Plugin#supported? return + # type could not be inferred + # @param context [LintRoller::Context] provided by the runner + def supported?(context) + context.engine == :rubocop + end + + # @param context [LintRoller::Context] provided by the runner + # + # @sg-ignore Declared return type ::LintRoller::Rules does not + # match inferred type Solargraph::LintRoller::Plugin for + # Solargraph::LintRoller::Plugin#rules + # @return [LintRoller::Rules] + def rules(context) + require 'solargraph/rubocop' + + cwd = __dir__ || '.' + + # @sg-ignore Unrecognized keyword argument type to Struct.new + ::LintRoller::Rules.new( + type: :path, + config_format: :rubocop, + value: Pathname.new(cwd).join("../../config/default.yml") + ) + end + end + end +end diff --git a/lib/solargraph/rubocop.rb b/lib/solargraph/rubocop.rb new file mode 100644 index 000000000..a180ada3a --- /dev/null +++ b/lib/solargraph/rubocop.rb @@ -0,0 +1 @@ +require_relative '../rubocop/solargraph_cops' diff --git a/rbs/shims/rubocop-ast/1.46/rubocop-ast.rbs b/rbs/shims/rubocop-ast/1.46/rubocop-ast.rbs new file mode 100644 index 000000000..19d2afcee --- /dev/null +++ b/rbs/shims/rubocop-ast/1.46/rubocop-ast.rbs @@ -0,0 +1,822 @@ +module RuboCop + module AST + class ProcessedSource + def initialize: (String source, Float ruby_version, ?path?) -> untyped + def raw_source: () -> String + def buffer: () -> Parser::Source::Buffer + def comments: () -> Array[Parser::Source::Comment & Node] + attr_reader ast: (Node | nil) + end + + class NodePattern + module Macros + def def_node_matcher: (Symbol, String) -> void + def def_node_search: (Symbol, String) -> void + end + + class Compiler + end + + def initialize: (String str, ?Compiler compiler) -> untyped + def match: (*untyped, **untyped) -> bool + | (*untyped, **untyped) { (*untyped) -> untyped } -> bool + end + + module Traversal + end + + module BasicLiteralNode + def value: () -> untyped + end + + module BinaryOperatorNode + def lhs: () -> Node + def rhs: () -> Node + def conditions: () -> Array[Node] + end + + module CollectionNode + end + + module ConditionalNode + def single_line_condition?: () -> bool + def multiline_condition?: () -> bool + def condition: () -> Node? + def body: () -> Node? + end + + module ConstantNode + def namespace: () -> Node? + def short_name: () -> Symbol + def module_name?: () -> bool + alias class_name? module_name? + def absolute?: () -> bool + def relative?: () -> bool + def each_path: () { (Node) -> void } -> self + | () -> ::Enumerator[Node, self] + end + + module Descendence + def each_child_node: (*Symbol types) { (Node) -> void } -> self + | (*Symbol types) -> ::Enumerator[Node, self] + def child_nodes: () -> Array[Node] + def each_descendant: (*Symbol types) { (Node) -> void } -> self + | (*Symbol types) -> ::Enumerator[Node, self] + def descendants: () -> Array[Node] + def each_node: (*Symbol types) { (Node) -> void } -> self + | (*Symbol types) -> ::Enumerator[Node, self] + end + + module HashElementNode + def key: () -> Node + def value: () -> Node + def same_line?: (Node other) -> bool + def key_delta: (Node other, ?Symbol alignment) -> Integer + def value_delta: (Node other) -> Integer + def delimiter_delta: (Node other) -> Integer + end + + module MethodDispatchNode + include MethodIdentifierPredicates + def receiver: () -> Node? + def method_name: () -> Symbol + def selector: () -> Parser::Source::Range + def block_node: () -> BlockNode? + def macro?: () -> bool + def access_modifier?: () -> bool + def bare_access_modifier?: () -> bool + def non_bare_access_modifier?: () -> bool + def special_modifier?: () -> bool + def command?: (Symbol name) -> bool + def setter_method?: () -> bool + alias assignment? setter_method? + def dot?: () -> bool + def double_colon?: () -> bool + def safe_navigation?: () -> bool + def self_receiver?: () -> bool + def const_receiver?: () -> bool + def implicit_call?: () -> bool + def block_literal?: () -> bool + def arithmetic_operation?: () -> bool + def def_modifier?: (?Node node) -> bool + def def_modifier: (?Node node) -> Node? + def lambda?: () -> bool + def lambda_literal?: () -> bool + def unary_operation?: () -> bool + def binary_operation?: () -> bool + end + + module MethodIdentifierPredicates + def method?: ((Symbol | String) name) -> bool + def operator_method?: () -> bool + def nonmutating_binary_operator_method?: () -> bool + def nonmutating_unary_operator_method?: () -> bool + def nonmutating_operator_method?: () -> bool + def nonmutating_array_method?: () -> bool + def nonmutating_hash_method?: () -> bool + def nonmutating_string_method?: () -> bool + def comparison_method?: () -> bool + def assignment_method?: () -> bool + def enumerator_method?: () -> bool + def enumerable_method?: () -> bool + def predicate_method?: () -> bool + def bang_method?: () -> bool + def camel_case_method?: () -> boolish + def self_receiver?: () -> boolish + def const_receiver?: () -> boolish + def negation_method?: () -> boolish + def prefix_not?: () -> boolish + def prefix_bang?: () -> boolish + end + + module ModifierNode + def modifier_form?: () -> bool + end + + module NumericNode + def sign?: () -> bool + end + + module ParameterizedNode + def parenthesized?: () -> bool + def first_argument: () -> Node? + def last_argument: () -> Node? + def arguments?: () -> bool + def splat_argument?: () -> bool + alias rest_argument? splat_argument? + def block_argument?: () -> bool + + module WrappedArguments + include ParameterizedNode + def arguments: () -> Array[Node] + end + + module RestArguments + include ParameterizedNode + def arguments: () -> Array[Node] + end + end + + module PredicateOperatorNode + def operator: () -> String + def logical_operator?: () -> bool + def semantic_operator?: () -> bool + end + + class Node < Parser::AST::Node + include Descendence + def type?: (*Symbol types) -> bool + def true_type?: () -> bool + def false_type?: () -> bool + def nil_type?: () -> bool + def int_type?: () -> bool + def float_type?: () -> bool + def str_type?: () -> bool + def dstr_type?: () -> bool + def sym_type?: () -> bool + def dsym_type?: () -> bool + def xstr_type?: () -> bool + def regopt_type?: () -> bool + def regexp_type?: () -> bool + def array_type?: () -> bool + def splat_type?: () -> bool + def pair_type?: () -> bool + def kwsplat_type?: () -> bool + def hash_type?: () -> bool + def irange_type?: () -> bool + def erange_type?: () -> bool + def self_type?: () -> bool + def lvar_type?: () -> bool + def ivar_type?: () -> bool + def cvar_type?: () -> bool + def gvar_type?: () -> bool + def const_type?: () -> bool + def defined_type?: () -> bool + def lvasgn_type?: () -> bool + def ivasgn_type?: () -> bool + def cvasgn_type?: () -> bool + def gvasgn_type?: () -> bool + def casgn_type?: () -> bool + def mlhs_type?: () -> bool + def masgn_type?: () -> bool + def op_asgn_type?: () -> bool + def and_asgn_type?: () -> bool + def ensure_type?: () -> bool + def rescue_type?: () -> bool + def arg_expr_type?: () -> bool + def or_asgn_type?: () -> bool + def back_ref_type?: () -> bool + def nth_ref_type?: () -> bool + def match_with_lvasgn_type?: () -> bool + def match_current_line_type?: () -> bool + def module_type?: () -> bool + def class_type?: () -> bool + def sclass_type?: () -> bool + def def_type?: () -> bool + def defs_type?: () -> bool + def undef_type?: () -> bool + def alias_type?: () -> bool + def args_type?: () -> bool + def cbase_type?: () -> bool + def arg_type?: () -> bool + def optarg_type?: () -> bool + def restarg_type?: () -> bool + def blockarg_type?: () -> bool + def block_pass_type?: () -> bool + def kwarg_type?: () -> bool + def kwoptarg_type?: () -> bool + def kwrestarg_type?: () -> bool + def kwnilarg_type?: () -> bool + def csend_type?: () -> bool + def super_type?: () -> bool + def zsuper_type?: () -> bool + def yield_type?: () -> bool + def block_type?: () -> bool + def and_type?: () -> bool + def not_type?: () -> bool + def or_type?: () -> bool + def if_type?: () -> bool + def when_type?: () -> bool + def case_type?: () -> bool + def while_type?: () -> bool + def until_type?: () -> bool + def while_post_type?: () -> bool + def until_post_type?: () -> bool + def for_type?: () -> bool + def break_type?: () -> bool + def next_type?: () -> bool + def redo_type?: () -> bool + def return_type?: () -> bool + def resbody_type?: () -> bool + def kwbegin_type?: () -> bool + def begin_type?: () -> bool + def retry_type?: () -> bool + def preexe_type?: () -> bool + def postexe_type?: () -> bool + def iflipflop_type?: () -> bool + def eflipflop_type?: () -> bool + def shadowarg_type?: () -> bool + def complex_type?: () -> bool + def rational_type?: () -> bool + def __FILE___type?: () -> bool + def __LINE___type?: () -> bool + def __ENCODING___type?: () -> bool + def ident_type?: () -> bool + def lambda_type?: () -> bool + def indexasgn_type?: () -> bool + def index_type?: () -> bool + def procarg0_type?: () -> bool + def restarg_expr_type?: () -> bool + def blockarg_expr_type?: () -> bool + def objc_kwarg_type?: () -> bool + def objc_restarg_type?: () -> bool + def objc_varargs_type?: () -> bool + def numargs_type?: () -> bool + def numblock_type?: () -> bool + def forward_args_type?: () -> bool + def forwarded_args_type?: () -> bool + def forward_arg_type?: () -> bool + def case_match_type?: () -> bool + def in_match_type?: () -> bool + def in_pattern_type?: () -> bool + def match_var_type?: () -> bool + def pin_type?: () -> bool + def match_alt_type?: () -> bool + def match_as_type?: () -> bool + def match_rest_type?: () -> bool + def array_pattern_type?: () -> bool + def match_with_trailing_comma_type?: () -> bool + def array_pattern_with_tail_type?: () -> bool + def hash_pattern_type?: () -> bool + def const_pattern_type?: () -> bool + def if_guard_type?: () -> bool + def unless_guard_type?: () -> bool + def match_nil_pattern_type?: () -> bool + def empty_else_type?: () -> bool + def find_pattern_type?: () -> bool + def kwargs_type?: () -> bool + def match_pattern_p_type?: () -> bool + def match_pattern_type?: () -> bool + def forwarded_restarg_type?: () -> bool + def forwarded_kwrestarg_type?: () -> bool + def itarg_type?: () -> bool + def itblock_type?: () -> bool + def send_type?: () -> bool + def parent: () -> Node? + def parent?: () -> bool + def root?: () -> bool + def to_a: () -> Array[Node] + alias node_parts to_a + def each_ancestor: (*Symbol types) { (Node) -> void } -> self + | (*Symbol types) -> ::Enumerator[Node, self] + def ancestors: () -> Array[Node] + def source: () -> String? + def source_range: () -> Parser::Source::Range + def first_line: () -> Integer + def last_line: () -> Integer + def line_count: () -> Integer + def nonempty_line_count: () -> Integer + def source_length: () -> Integer + def receiver: () -> Node? + def str_content: () -> (String | false) + def const_name: () -> String? + def defined_module: () -> ConstNode? + def defined_module_name: () -> String? + def parent_module_name: () -> String + def multiline?: () -> bool + def single_line?: () -> bool + def empty_source?: () -> bool + def assignment_or_similar?: () -> bool + def literal?: () -> bool + def basic_literal?: () -> bool + def truthy_literal?: () -> bool + def falsey_literal?: () -> bool + def mutable_literal?: () -> bool + def immutable_literal?: () -> bool + def recursive_literal?: () -> bool + def recursive_basic_literal?: () -> bool + def variable?: () -> bool + def reference?: () -> bool + def equals_asgn?: () -> bool + def shorthand_asgn?: () -> bool + def assignment?: () -> bool + def basic_conditional?: () -> bool + def conditional?: () -> bool + def post_condition_loop?: () -> bool + def loop_keyword?: () -> bool + def keyword?: () -> bool + def special_keyword?: () -> bool + def operator_keyword?: () -> bool + def parenthesized_call?: () -> bool + def call_type?: () -> bool + def chained?: () -> bool + def argument?: () -> bool + def argument_type?: () -> bool + def boolean_type?: () -> bool + def numeric_type?: () -> bool + def range_type?: () -> bool + def guard_clause?: () -> bool + def match_guard_clause?: () -> bool + def proc?: () -> bool + def lambda?: () -> bool + def lambda_or_proc?: () -> bool + def global_const?: (untyped) -> bool + def class_constructor?: () -> bool + def struct_constructor?: () -> bool + def class_definition?: () -> bool + def module_definition?: () -> bool + def value_used?: () -> bool + def pure?: () -> bool + def sibling_index: () -> (Integer | nil) + def right_sibling: () -> (Node | nil) + def left_sibling: () -> (Node | nil) + def left_siblings: () -> Array[Node] + def right_siblings: () -> Array[Node] + end + + class AliasNode < Node + def old_identifier: () -> SymbolNode + def new_identifier: () -> SymbolNode + end + + class AndAsgnNode < OpAsgnNode + def operator: () -> :'&&' + end + + class AndNode < Node + include BinaryOperatorNode + include PredicateOperatorNode + def alternate_operator: () -> String + def inverse_operator: () -> String + end + + class ArgNode < Node + def name: () -> Symbol? + def default_value: () -> Node? + def default?: () -> bool + end + + class ArgsNode < Node + include CollectionNode + def empty_and_without_delimiters?: () -> bool + def argument_list: () -> Array[Node] + end + + class ArrayNode < Node + alias values children + def each_value: () { (Node) -> void } -> self + | () -> ::Enumerator[Node, self] + def square_brackets?: () -> bool + def percent_literal?: (?Symbol type) -> bool + def bracketed?: () -> bool + def location: () -> Parser::Source::Map::Collection + alias loc location + end + + class AsgnNode < Node + def name: () -> Symbol + alias lhs name + def expression: () -> Node + alias rhs expression + end + + class BlockNode < Node + include MethodIdentifierPredicates + def send_node: () -> SendNode + def first_argument: () -> Node? + def last_argument: () -> Node? + def arguments: () -> Array[Node] + def argument_list: () -> Array[Node] + def body: () -> Node? + def method_name: () -> Symbol + def arguments?: () -> bool + def braces?: () -> bool + def keywords?: () -> bool + def delimiters: () -> Array[String] + def opening_delimiter: () -> String + def closing_delimiter: () -> String + def single_line?: () -> bool + def multiline?: () -> bool + def lambda?: () -> bool + def void_context?: () -> bool + def location: () -> Parser::Source::Map::Collection + alias loc location + end + + class BreakNode < Node + include ParameterizedNode::WrappedArguments + end + + class CaseMatchNode < Node + include ConditionalNode + def keyword: () -> 'case' + def in_pattern_branches: () -> Array[InPatternNode] + def branches: () -> Array[Node | nil] + def else_branch: () -> Node? + def else?: () -> bool + end + + class CaseNode < Node + include ConditionalNode + def keyword: () -> 'case' + def when_branches: () -> Array[WhenNode] + def branches: () -> Array[Node | nil] + def else_branch: () -> Node? + def else?: () -> bool + end + + class CasgnNode < Node + include ConstantNode + alias name short_name + alias lhs short_name + def expression: () -> Node + alias rhs expression + end + + class ClassNode < Node + def identifier: () -> Node + def parent_class: () -> Node? + def body: () -> Node? + end + + class ComplexNode < Node + include BasicLiteralNode + include NumericNode + end + + class ConstNode < Node + include ConstantNode + end + + class CsendNode < SendNode + def send_type?: () -> false + end + + class DefNode < Node + include ParameterizedNode + include MethodIdentifierPredicates + def void_context?: () -> bool + def argument_forwarding?: () -> bool + def method_name: () -> Symbol + def arguments: () -> ArgsNode + def body: () -> Node + def receiver: () -> (Node | nil) + def endless?: () -> bool + def location: () -> Parser::Source::Map::MethodDefinition + alias loc location + end + + class DefinedNode < Node + include ParameterizedNode + include MethodDispatchNode + def node_parts: () -> Array[Node | nil] + alias arguments children + end + + class DstrNode < Node + def value: () -> String + def location: () -> (Parser::Source::Map::Collection | Parser::Source::Map::Heredoc) + alias loc location + end + + class EnsureNode < Node + def body: () -> Node? + def branch: () -> Node? + def rescue_node: () -> Node? + def void_context?: () -> true + end + + class FloatNode < Node + include BasicLiteralNode + include NumericNode + end + + class ForNode < Node + def keyword: () -> 'for' + def do?: () -> bool + def void_context?: () -> true + def variable: () -> Node + def collection: () -> Node + def body: () -> Node? + end + + class ForwardArgsNode < Node + include CollectionNode + def to_a: () -> [self] + end + + class HashNode < Node + def pairs: () -> Array[PairNode] + def empty?: () -> bool + def each_pair: () { (Node, Node) -> void } -> self + | () -> ::Enumerator[PairNode, self] + def keys: () -> Array[Node] + def each_key: () { (Node) -> void } -> self + | () -> ::Enumerator[Node, self] + def values: () -> Array[Node] + def each_value: () { (Node) -> void } -> self + | () -> ::Enumerator[Node, self] + def pairs_on_same_line?: () -> bool + def mixed_delimiters?: () -> bool + def braces?: () -> bool + def location: () -> Parser::Source::Map::Collection + alias loc location + end + + class IfNode < Node + include ConditionalNode + include ModifierNode + def if?: () -> bool + def unless?: () -> bool + def then?: () -> bool + def elsif?: () -> bool + def else?: () -> bool + def ternary?: () -> bool + def keyword: () -> String + def inverse_keyword: () -> String + def modifier_form?: () -> bool + def nested_conditional?: () -> bool + def elsif_conditional?: () -> bool + def if_branch: () -> Node? + def else_branch: () -> Node? + def node_parts: () -> Array[Node] + def branches: () -> Array[Node] + def location: () -> (Parser::Source::Map::Condition | Parser::Source::Map::Keyword | Parser::Source::Map::Ternary) + alias loc location + end + + class InPatternNode < Node + def pattern: () -> Node + def branch_index: () -> Integer + def then?: () -> bool + def body: () -> Node? + end + + class IndexNode < Node + include ParameterizedNode::RestArguments + include MethodDispatchNode + def attribute_accessor?: () -> false + def assignment_method?: () -> false + def method_name: () -> :[] + end + + class IndexasgnNode < Node + include ParameterizedNode::RestArguments + include MethodDispatchNode + def attribute_accessor?: () -> false + def assignment_method?: () -> true + def method_name: () -> :[]= + end + + class IntNode < Node + include BasicLiteralNode + include NumericNode + end + + class KeywordBeginNode < Node + def body: () -> Node? + def ensure_node: () -> Node? + def rescue_node: () -> Node? + end + + class KeywordSplatNode < Node + include HashElementNode + def hash_rocket?: () -> false + def colon?: () -> false + def operator: () -> String + def node_parts: () -> [self, self] + def kwsplat_type?: () -> true + end + + class LambdaNode < Node + include ParameterizedNode::RestArguments + include MethodDispatchNode + def lambda?: () -> true + def lambda_literal?: () -> true + def attribute_accessor?: () -> false + def assignment_method?: () -> false + def receiver: () -> nil + def method_name: () -> :lambda + end + + class MasgnNode < Node + def lhs: () -> MlhsNode + def assignments: () -> Array[Node] + def names: () -> Array[Symbol] + def expression: () -> Node + alias rhs expression + def values: () -> Array[Node] + end + + class MlhsNode < Node + def assignments: () -> Array[Node] + end + + class ModuleNode < Node + def identifier: () -> Node + def body: () -> Node? + end + + class NextNode < Node + include ParameterizedNode::WrappedArguments + end + + class OpAsgnNode < Node + def assignment_node: () -> AsgnNode + alias lhs assignment_node + def name: () -> Symbol + def operator: () -> Symbol + def expression: () -> Node + alias rhs expression + end + + class OrAsgnNode < OpAsgnNode + def operator: () -> :'||' + end + + class OrNode < Node + include BinaryOperatorNode + include PredicateOperatorNode + def alternate_operator: () -> String + def inverse_operator: () -> String + end + + class RationalNode < Node + include BasicLiteralNode + include NumericNode + end + + class PairNode < Node + include HashElementNode + def hash_rocket?: () -> bool + def colon?: () -> bool + def delimiter: (?with_spacing: bool) -> String + def inverse_delimiter: (?with_spacing: bool) -> String + def value_on_new_line?: () -> bool + def value_omission?: () -> bool + def location: () -> Parser::Source::Map::Operator + alias loc location + end + + class Procarg0Node < ArgNode + def name: () -> Symbol? + end + + class RangeNode < Node + def begin: () -> Node? + def end: () -> Node? + end + + class RegexpNode < Node + def to_regexp: () -> ::Regexp + def regopt: () -> Node + def options: () -> Integer + def content: () -> String + def slash_literal?: () -> bool + def percent_r_literal?: () -> bool + def delimiters: () -> String + def delimiter?: (String char) -> bool + def interpolation?: () -> bool + def multiline_mode?: () -> bool + def extended?: () -> bool + def ignore_case?: () -> bool + def single_interpolation?: () -> bool + def no_encoding?: () -> bool + def fixed_encoding?: () -> bool + def location: () -> Parser::Source::Map::Collection + alias loc location + end + + class ResbodyNode < Node + def body: () -> Node? + def exceptions: () -> Array[Node] + def exception_variable: () -> Node? + def branch_index: () -> Integer + end + + class RescueNode < Node + def body: () -> Node? + def resbody_branches: () -> Array[ResbodyNode] + def branches: () -> Array[Node | nil] + def else_branch: () -> Node? + def else?: () -> bool + end + + class ReturnNode < Node + include ParameterizedNode::WrappedArguments + end + + class SelfClassNode < Node + def identifier: () -> Node + def body: () -> Node? + end + + class SendNode < Node + include ParameterizedNode::RestArguments + include MethodDispatchNode + def send_type?: () -> true + def location: () -> Parser::Source::Map::Send + alias loc location + end + + class StrNode < Node + include BasicLiteralNode + def value: () -> (String | StrNode) + def single_quoted?: () -> bool + def double_quoted?: () -> bool + def character_literal?: () -> bool + def heredoc?: () -> bool + def percent_literal?: (?Symbol type) -> bool + def location: () -> (Parser::Source::Map::Collection | Parser::Source::Map::Heredoc) + alias loc location + end + + class SuperNode < Node + include ParameterizedNode + include MethodDispatchNode + def node_parts: () -> Array[untyped] + alias arguments children + end + + class SymbolNode < Node + include BasicLiteralNode + def value: () -> Symbol + def location: () -> Parser::Source::Map::Collection + alias loc location + end + + class UntilNode < Node + include ConditionalNode + include ModifierNode + def keyword: () -> 'until' + def inverse_keyword: () -> 'while' + def do?: () -> bool + end + + class VarNode < Node + def name: () -> Symbol + end + + class WhenNode < Node + def conditions: () -> Array[Node] + def branch_index: () -> Integer + def then?: () -> bool + def body: () -> Node? + end + + class WhileNode < Node + include ConditionalNode + include ModifierNode + def keyword: () -> 'while' + def inverse_keyword: () -> 'until' + def do?: () -> bool + end + + class YieldNode < Node + include ParameterizedNode + include MethodDispatchNode + def node_parts: () -> Array[untyped] + alias arguments children + end + end +end diff --git a/rbs/shims/rubocop/1.57/rubocop.rbs b/rbs/shims/rubocop/1.57/rubocop.rbs new file mode 100644 index 000000000..bfbd622be --- /dev/null +++ b/rbs/shims/rubocop/1.57/rubocop.rbs @@ -0,0 +1,132 @@ +module RuboCop + class ConfigLoader + def self.debug?: () -> boolish + def self.merge_with_default: (Config, String) -> Config + end + + class Config + def initialize: (Hash[untyped, untyped], String) -> void + def for_cop: (String cop) -> Hash[String, untyped] + def for_enabled_cop: (String cop) -> Hash[String, untyped] + end + + module Cop + class Base + extend AST::NodePattern::Macros + include Util + include IgnoredNode + include AutocorrectLogic + + def self.exclude_from_registry: () -> void + def self.department: () -> Symbol + def self.cop_name: () -> String + def self.documentation_url: (?Config?) -> String + def self.requires_gem: (String gem_name, *String version_requirements) -> void + + attr_reader config: Config + + def add_offense: (untyped node, ?message: String, ?severity: Symbol) -> void + | (untyped node, ?message: String, ?severity: Symbol) { (Corrector) -> void } -> void + def cop_config: () -> Hash[String, untyped] + def target_ruby_version: () -> Float + def processed_source: () -> AST::ProcessedSource + def target_gem_version: (String gem_name) -> Gem::Version + def on_new_investigation: () -> void + def on_investigation_end: () -> void + def on_other_file: () -> void + end + + module AutocorrectLogic + def autocorrect?: () -> bool + def autocorrect_with_disable_uncorrectable?: () -> bool + def autocorrect_requested?: () -> bool + def correctable?: () -> bool + def disable_uncorrectable?: () -> bool + def safe_autocorrect?: () -> bool + def autocorrect_enabled?: () -> bool + end + + class Corrector < Parser::Source::TreeRewriter + def replace: ((Parser::Source::Range | RuboCop::AST::Node) range, String content) -> self + def wrap: ((Parser::Source::Range | RuboCop::AST::Node) range, String? insert_before, String? insert_after) -> self + def remove: ((Parser::Source::Range | RuboCop::AST::Node) range) -> self + def insert_before: ((Parser::Source::Range | RuboCop::AST::Node) range, String content) -> self + def insert_after: ((Parser::Source::Range | RuboCop::AST::Node) range, String content) -> self + def remove_preceding: ((Parser::Source::Range | RuboCop::AST::Node) node_or_range, Integer size) -> self + def remove_leading: ((Parser::Source::Range | RuboCop::AST::Node) node_or_range, Integer size) -> self + def remove_trailing: ((Parser::Source::Range | RuboCop::AST::Node) node_or_range, Integer size) -> self + def swap: ((Parser::Source::Range | RuboCop::AST::Node) node_or_range1, (Parser::Source::Range | RuboCop::AST::Node) node_or_range2) -> self + end + + module Alignment + def configured_indentation_width: () -> Integer + def indentation: (RuboCop::AST::Node node) -> String + def offset: (RuboCop::AST::Node node) -> String + end + + module ConfigurableEnforcedStyle + def style: () -> Symbol + end + + module CommentsHelp + def source_range_with_comment: (RuboCop::AST::Node node) -> Parser::Source::Range + def contains_comments?: (RuboCop::AST::Node node) -> bool + def comments_in_range: (RuboCop::AST::Node node) -> Array[Parser::Source::Comment] + def comments_contain_disables?: (RuboCop::AST::Node node, String cop_name) -> bool + end + + module RangeHelp + def source_range: (Parser::Source::Buffer source_buffer, Integer line_number, Integer column, ?Integer length) -> Parser::Source::Range + def range_between: (Integer start_pos, Integer end_pos) -> Parser::Source::Range + def range_with_surrounding_space: (?Parser::Source::Range range_positional, + ?range: Parser::Source::Range, ?side: Symbol, ?newlines: bool, + ?whitespace: bool, ?continuations: bool, + ?buffer: Parser::Source::Buffer) -> Parser::Source::Range + def range_by_whole_lines: (Parser::Source::Range range, + ?include_final_newline: bool, + ?buffer: Parser::Source::Buffer) -> Parser::Source::Range + end + + module IgnoredNode + def ignore_node: (RuboCop::AST::Node node) -> void + def part_of_ignored_node?: (RuboCop::AST::Node node) -> bool + def ignored_node?: (RuboCop::AST::Node node) -> bool + end + + module TargetRubyVersion + def minimum_target_ruby_version: (Float) -> void + def maximum_target_ruby_version: (Float) -> void + end + + module Util + include PathUtil + def line_range: (RuboCop::AST::Node node) -> ::Range[Integer] + def parentheses?: (RuboCop::AST::Node node) -> bool + def add_parentheses: (RuboCop::AST::Node node, Corrector corrector) -> void + def any_descendant?: (RuboCop::AST::Node node, *Symbol types) -> bool + def args_begin: (RuboCop::AST::Node node) -> Parser::Source::Range + def args_end: (RuboCop::AST::Node node) -> Parser::Source::Range + def begins_its_line?: (Parser::Source::Range range) -> bool + def first_part_of_call_chain: (RuboCop::AST::Node node) -> RuboCop::AST::Node + def double_quotes_required?: (String string) -> bool + def needs_escaping?: (String string) -> bool + def escape_string: (String string) -> String + def to_string_literal: (String string) -> String + def trim_string_interpolation_escape_character: (String str) -> String + def interpret_string_escapes: (String string) -> String + def line: ((RuboCop::AST::Node | Parser::Source::Range) node_or_range) -> Integer + def same_line?: ((RuboCop::AST::Node | Parser::Source::Range) node1, (RuboCop::AST::Node | Parser::Source::Range) node2) -> bool + def indent: (RuboCop::AST::Node node, ?offset: Integer) -> String + end + end + + class ProcessedSource = AST::ProcessedSource + + module AutoCorrector + def support_autocorrect?: () -> true + end + + module PathUtil + def smart_path: (String path) -> String + end +end diff --git a/solargraph.gemspec b/solargraph.gemspec index a3e8e88cd..aa529f268 100755 --- a/solargraph.gemspec +++ b/solargraph.gemspec @@ -21,6 +21,7 @@ Gem::Specification.new do |s| s.homepage = 'https://solargraph.org' s.license = 'MIT' s.executables = ['solargraph'] + s.metadata["default_lint_roller_plugin"] = "Solargraph::LintRoller::Plugin" s.metadata["funding_uri"] = "https://www.patreon.com/castwide" s.metadata["bug_tracker_uri"] = "https://github.com/castwide/solargraph/issues" s.metadata["changelog_uri"] = "https://github.com/castwide/solargraph/blob/master/CHANGELOG.md" @@ -37,6 +38,7 @@ Gem::Specification.new do |s| s.add_runtime_dependency 'jaro_winkler', '~> 1.6', '>= 1.6.1' s.add_runtime_dependency 'kramdown', '~> 2.3' s.add_runtime_dependency 'kramdown-parser-gfm', '~> 1.1' + s.add_runtime_dependency 'lint_roller' s.add_runtime_dependency 'logger', '~> 1.6' s.add_runtime_dependency 'observer', '~> 0.1' s.add_runtime_dependency 'ostruct', '~> 0.6' @@ -46,6 +48,7 @@ Gem::Specification.new do |s| s.add_runtime_dependency 'rbs', ['>= 3.6.1', '<= 4.0.0.dev.5'] s.add_runtime_dependency 'reverse_markdown', '~> 3.0' s.add_runtime_dependency 'rubocop', '~> 1.76' + s.add_runtime_dependency 'rubocop-ast' s.add_runtime_dependency 'thor', '~> 1.0' s.add_runtime_dependency 'tilt', '~> 2.0' s.add_runtime_dependency 'yard', '~> 0.9', '>= 0.9.24'