-
-
Notifications
You must be signed in to change notification settings - Fork 25
/
MethodAnnotationProvider.js
135 lines (108 loc) · 4.42 KB
/
MethodAnnotationProvider.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/* global atom */
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* DS205: Consider reworking code to avoid use of IIFEs
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
let MethodProvider;
const AbstractAnnotationProvider = require('./AbstractAnnotationProvider');
module.exports =
//#*
// Provides annotations for member methods that are overrides or interface implementations.
//#
(MethodProvider = class MethodProvider extends AbstractAnnotationProvider {
/**
* @inheritdoc
*/
registerAnnotations(editor) {
const path = editor.getPath();
if (!path) { return null; }
const successHandler = classInfo => {
if (!classInfo) { return null; }
return (() => {
const result = [];
for (let name in classInfo.methods) {
const method = classInfo.methods[name];
if (!method.override && ((method.implementations != null ? method.implementations.length : undefined) === 0)) { continue; }
if (method.declaringStructure.fqcn !== classInfo.fqcn) { continue; }
const {Range} = require('atom');
const range = new Range([method.range.start.line, 0], [method.range.start.line + 1, -1]);
result.push(this.placeAnnotation(editor, range, this.extractAnnotationInfo(method)));
}
return result;
})();
};
const failureHandler = () => {};
// Just do nothing.
const getClassListHandler = classesInEditor => {
const promises = [];
for (let fqcn in classesInEditor) {
const classInfo = classesInEditor[fqcn];
promises.push(this.service.getClassInfo(fqcn).then(successHandler, failureHandler));
}
return Promise.all(promises);
};
return this.service.getClassListForFile('file://' + path).then(getClassListHandler, failureHandler);
}
/**
* Fetches annotation info for the specified context.
*
* @param {Object} context
*
* @return {Object}
*/
extractAnnotationInfo(context) {
let extraData = null;
let tooltipText = '';
let lineNumberClass = '';
if (context.override) {
// NOTE: We deliberately show the declaring class here, not the structure (which could be a trait). However,
// if the method is overriding a trait method from the *same* class, we show the trait name, as it would be
// strange to put an annotation in "Foo" saying "Overrides method from Foo".
let overriddenFromFqcn = context.override.declaringClass.fqcn;
if (overriddenFromFqcn === context.declaringClass.fqcn) {
overriddenFromFqcn = context.override.declaringStructure.fqcn;
}
extraData = context.override;
if (!context.override.wasAbstract) {
lineNumberClass = 'override';
tooltipText = `Overrides method from ${overriddenFromFqcn}`;
} else {
lineNumberClass = 'abstract-override';
tooltipText = `Implements abstract method from ${overriddenFromFqcn}`;
}
} else {
// NOTE: We deliberately show the declaring class here, not the structure (which could be a trait).
extraData = context.implementations[0];
lineNumberClass = 'implementations';
tooltipText = `Implements method for ${extraData.declaringStructure.fqcn}`;
}
extraData.fqcn = context.fqcn;
return {
lineNumberClass,
tooltipText,
extraData
};
}
/**
* @inheritdoc
*/
handleMouseClick(event, editor, annotationInfo) {
const {Convert} = require('atom-languageclient');
return atom.workspace.open(Convert.uriToPath(annotationInfo.extraData.declaringStructure.uri), {
initialLine : annotationInfo.extraData.declaringStructure.memberRange.start.line,
searchAllPanes : true
});
}
/**
* @inheritdoc
*/
removePopover() {
if (this.attachedPopover) {
this.attachedPopover.dispose();
return this.attachedPopover = null;
}
}
});